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 1 commit
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
15 changes: 15 additions & 0 deletions op-deployer/pkg/deployer/bootstrap/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ var DisputeGameFlags = []cli.Flag{
ChallengerFlag,
}

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

var Commands = []*cli.Command{
{
Name: "opcm",
Expand All @@ -200,4 +209,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,
},
}
191 changes: 191 additions & 0 deletions op-deployer/pkg/deployer/bootstrap/mips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package bootstrap

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

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

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

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

"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

MinProposalSizeBytes uint64
ChallengePeriodSeconds uint64
MipsVersion uint8
}

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")
}

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)
}

ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)

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

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)
}
chainIDU64 := chainID.Uint64()

standardVersionsTOML, err := standard.L1VersionsDataFor(chainIDU64)
if err != nil {
return fmt.Errorf("error getting standard versions TOML: %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{
Release: release,
StandardVersionsToml: standardVersionsTOML,
MipsVersion: cfg.MipsVersion,
MinProposalSizeBytes: cfg.MinProposalSizeBytes,
ChallengePeriodSeconds: cfg.ChallengePeriodSeconds,
},
)
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
}
69 changes: 69 additions & 0 deletions op-deployer/pkg/deployer/opcm/mips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package opcm

import (
"fmt"

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

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

type DeployMIPSInput struct {
Release string
StandardVersionsToml string
MipsVersion uint8
MinProposalSizeBytes uint64
ChallengePeriodSeconds uint64
}

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

type DeployMIPSOutput struct {
MipsSingleton common.Address
PreimageOracleSingleton 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
}
44 changes: 44 additions & 0 deletions op-deployer/pkg/deployer/opcm/mips_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package opcm

import (
"testing"

"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"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)

standardVersionsTOML, err := standard.L1VersionsDataFor(11155111)
require.NoError(t, err)

input := DeployMIPSInput{
Release: "dev",
StandardVersionsToml: standardVersionsTOML,
MipsVersion: 1,
MinProposalSizeBytes: standard.MinProposalSizeBytes,
ChallengePeriodSeconds: standard.ChallengePeriodSeconds,
}

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

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