Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

op-deployer: Add deploy mips script #12835

Merged
merged 3 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion op-deployer/pkg/deployer/bootstrap/dispute_game.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type DisputeGameConfig struct {

MinProposalSizeBytes uint64
ChallengePeriodSeconds uint64
MipsVersion uint8
MipsVersion uint64
GameKind string
GameType uint32
AbsolutePrestate common.Hash
Expand Down
21 changes: 21 additions & 0 deletions op-deployer/pkg/deployer/bootstrap/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
L2ChainIdFlagName = "l2-chain-id"
ProposerFlagName = "proposer"
ChallengerFlagName = "challenger"
PreimageOracleFlagName = "preimage-oracle"
)

var (
Expand Down Expand Up @@ -140,6 +141,12 @@ var (
EnvVars: deployer.PrefixEnvVar("CHALLENGER"),
Value: common.Address{}.Hex(),
}
PreimageOracleFlag = &cli.StringFlag{
Name: PreimageOracleFlagName,
Usage: "Preimage oracle address.",
EnvVars: deployer.PrefixEnvVar("PREIMAGE_ORACLE"),
Value: common.Address{}.Hex(),
}
)

var OPCMFlags = []cli.Flag{
Expand Down Expand Up @@ -181,6 +188,14 @@ var DisputeGameFlags = []cli.Flag{
ChallengerFlag,
}

var MIPSFlags = []cli.Flag{
deployer.L1RPCURLFlag,
deployer.PrivateKeyFlag,
ArtifactsLocatorFlag,
PreimageOracleFlag,
MIPSVersionFlag,
}

var Commands = []*cli.Command{
{
Name: "opcm",
Expand All @@ -200,4 +215,10 @@ var Commands = []*cli.Command{
Flags: cliapp.ProtectFlags(DisputeGameFlags),
Action: DisputeGameCLI,
},
{
Name: "mips",
Usage: "Bootstrap an instance of MIPS.",
Flags: cliapp.ProtectFlags(MIPSFlags),
Action: MIPSCLI,
},
}
196 changes: 196 additions & 0 deletions op-deployer/pkg/deployer/bootstrap/mips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package bootstrap

import (
"context"
"crypto/ecdsa"
"fmt"
"strings"

artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum/go-ethereum/common"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
"github.com/ethereum-optimism/optimism/op-service/ctxinterrupt"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum-optimism/optimism/op-service/jsonutil"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)

type MIPSConfig struct {
L1RPCUrl string
PrivateKey string
Logger log.Logger
ArtifactsLocator *artifacts2.Locator

privateKeyECDSA *ecdsa.PrivateKey

PreimageOracle common.Address
MipsVersion uint64
}

func (c *MIPSConfig) Check() error {
if c.L1RPCUrl == "" {
return fmt.Errorf("l1RPCUrl must be specified")
}

if c.PrivateKey == "" {
return fmt.Errorf("private key must be specified")
}

privECDSA, err := crypto.HexToECDSA(strings.TrimPrefix(c.PrivateKey, "0x"))
if err != nil {
return fmt.Errorf("failed to parse private key: %w", err)
}
c.privateKeyECDSA = privECDSA

if c.Logger == nil {
return fmt.Errorf("logger must be specified")
}

if c.ArtifactsLocator == nil {
return fmt.Errorf("artifacts locator must be specified")
}

if c.PreimageOracle == (common.Address{}) {
return fmt.Errorf("preimage oracle must be specified")
}

if c.MipsVersion == 0 {
return fmt.Errorf("mips version must be specified")
}
if c.MipsVersion != 1 && c.MipsVersion != 2 {
return fmt.Errorf("mips version must be either 1 or 2")
}

return nil
}

func MIPSCLI(cliCtx *cli.Context) error {
logCfg := oplog.ReadCLIConfig(cliCtx)
l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg)
oplog.SetGlobalLogHandler(l.Handler())

l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName)
privateKey := cliCtx.String(deployer.PrivateKeyFlagName)
artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName)
artifactsLocator := new(artifacts2.Locator)
if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil {
return fmt.Errorf("failed to parse artifacts URL: %w", err)
}

mipsVersion := cliCtx.Uint64(MIPSVersionFlagName)
preimageOracle := common.HexToAddress(cliCtx.String(PreimageOracleFlagName))

ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)

return MIPS(ctx, MIPSConfig{
L1RPCUrl: l1RPCUrl,
PrivateKey: privateKey,
Logger: l,
ArtifactsLocator: artifactsLocator,
MipsVersion: mipsVersion,
PreimageOracle: preimageOracle,
})
}

func MIPS(ctx context.Context, cfg MIPSConfig) error {
if err := cfg.Check(); err != nil {
return fmt.Errorf("invalid config for MIPS: %w", err)
}

lgr := cfg.Logger
progressor := func(curr, total int64) {
lgr.Info("artifacts download progress", "current", curr, "total", total)
}

artifactsFS, cleanup, err := artifacts2.Download(ctx, cfg.ArtifactsLocator, progressor)
if err != nil {
return fmt.Errorf("failed to download artifacts: %w", err)
}
defer func() {
if err := cleanup(); err != nil {
lgr.Warn("failed to clean up artifacts", "err", err)
}
}()

l1Client, err := ethclient.Dial(cfg.L1RPCUrl)
if err != nil {
return fmt.Errorf("failed to connect to L1 RPC: %w", err)
}

chainID, err := l1Client.ChainID(ctx)
if err != nil {
return fmt.Errorf("failed to get chain ID: %w", err)
}

signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID))
chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey)

bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{
Logger: lgr,
ChainID: chainID,
Client: l1Client,
Signer: signer,
From: chainDeployer,
})
if err != nil {
return fmt.Errorf("failed to create broadcaster: %w", err)
}

nonce, err := l1Client.NonceAt(ctx, chainDeployer, nil)
if err != nil {
return fmt.Errorf("failed to get starting nonce: %w", err)
}

host, err := env.DefaultScriptHost(
bcaster,
lgr,
chainDeployer,
artifactsFS,
nonce,
)
if err != nil {
return fmt.Errorf("failed to create script host: %w", err)
}

var release string
if cfg.ArtifactsLocator.IsTag() {
release = cfg.ArtifactsLocator.Tag
} else {
release = "dev"
}

lgr.Info("deploying dispute game", "release", release)

dgo, err := opcm.DeployMIPS(
host,
opcm.DeployMIPSInput{
MipsVersion: cfg.MipsVersion,
PreimageOracle: cfg.PreimageOracle,
},
)
if err != nil {
return fmt.Errorf("error deploying dispute game: %w", err)
}

if _, err := bcaster.Broadcast(ctx); err != nil {
return fmt.Errorf("failed to broadcast: %w", err)
}

lgr.Info("deployed dispute game")

if err := jsonutil.WriteJSON(dgo, ioutil.ToStdOut()); err != nil {
return fmt.Errorf("failed to write output: %w", err)
}
return nil
}
2 changes: 1 addition & 1 deletion op-deployer/pkg/deployer/opcm/dispute_game.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
type DeployDisputeGameInput struct {
Release string
StandardVersionsToml string
MipsVersion uint8
MipsVersion uint64
MinProposalSizeBytes uint64
ChallengePeriodSeconds uint64
GameKind string
Expand Down
65 changes: 65 additions & 0 deletions op-deployer/pkg/deployer/opcm/mips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package opcm

import (
"fmt"

"github.com/ethereum/go-ethereum/common"

"github.com/ethereum-optimism/optimism/op-chain-ops/script"
)

type DeployMIPSInput struct {
MipsVersion uint64
PreimageOracle common.Address
}

func (input *DeployMIPSInput) InputSet() bool {
return true
}

type DeployMIPSOutput struct {
MipsSingleton common.Address
}

func (output *DeployMIPSOutput) CheckOutput(input common.Address) error {
return nil
}

type DeployMIPSScript struct {
Run func(input, output common.Address) error
}

func DeployMIPS(
host *script.Host,
input DeployMIPSInput,
) (DeployMIPSOutput, error) {
var output DeployMIPSOutput
inputAddr := host.NewScriptAddress()
outputAddr := host.NewScriptAddress()

cleanupInput, err := script.WithPrecompileAtAddress[*DeployMIPSInput](host, inputAddr, &input)
if err != nil {
return output, fmt.Errorf("failed to insert DeployMIPSInput precompile: %w", err)
}
defer cleanupInput()

cleanupOutput, err := script.WithPrecompileAtAddress[*DeployMIPSOutput](host, outputAddr, &output,
script.WithFieldSetter[*DeployMIPSOutput])
if err != nil {
return output, fmt.Errorf("failed to insert DeployMIPSOutput precompile: %w", err)
}
defer cleanupOutput()

implContract := "DeployMIPS"
deployScript, cleanupDeploy, err := script.WithScript[DeployMIPSScript](host, "DeployMIPS.s.sol", implContract)
if err != nil {
return output, fmt.Errorf("failed to load %s script: %w", implContract, err)
}
defer cleanupDeploy()

if err := deployScript.Run(inputAddr, outputAddr); err != nil {
return output, fmt.Errorf("failed to run %s script: %w", implContract, err)
}

return output, nil
}
36 changes: 36 additions & 0 deletions op-deployer/pkg/deployer/opcm/mips_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package opcm

import (
"testing"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)

func TestDeployMIPS(t *testing.T) {
_, artifacts := testutil.LocalArtifacts(t)

host, err := env.DefaultScriptHost(
broadcaster.NoopBroadcaster(),
testlog.Logger(t, log.LevelInfo),
common.Address{'D'},
artifacts,
0,
)
require.NoError(t, err)

input := DeployMIPSInput{
MipsVersion: 1,
PreimageOracle: common.Address{0xab},
}

output, err := DeployMIPS(host, input)
require.NoError(t, err)

require.NotEmpty(t, output.MipsSingleton)
}
Loading