Commit 7726c1aa authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-deployer: Simplify and fix bootstrap disputegame (#13094)

* op-deployer: Load CLI options into the bootstrap disputegame config

* op-deployer: Simplify bootstrap disputegame to only deploy the disputegame contract
parent f633e856
...@@ -69,22 +69,31 @@ func DelayedWETHCLI(cliCtx *cli.Context) error { ...@@ -69,22 +69,31 @@ func DelayedWETHCLI(cliCtx *cli.Context) error {
l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg)
oplog.SetGlobalLogHandler(l.Handler()) oplog.SetGlobalLogHandler(l.Handler())
config, err := NewDelayedWETHConfigFromClI(cliCtx, l)
if err != nil {
return err
}
ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)
return DelayedWETH(ctx, config)
}
func NewDelayedWETHConfigFromClI(cliCtx *cli.Context, l log.Logger) (DelayedWETHConfig, error) {
l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName)
privateKey := cliCtx.String(deployer.PrivateKeyFlagName) privateKey := cliCtx.String(deployer.PrivateKeyFlagName)
artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName) artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName)
artifactsLocator := new(artifacts2.Locator) artifactsLocator := new(artifacts2.Locator)
if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil {
return fmt.Errorf("failed to parse artifacts URL: %w", err) return DelayedWETHConfig{}, fmt.Errorf("failed to parse artifacts URL: %w", err)
} }
config := DelayedWETHConfig{
ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)
return DelayedWETH(ctx, DelayedWETHConfig{
L1RPCUrl: l1RPCUrl, L1RPCUrl: l1RPCUrl,
PrivateKey: privateKey, PrivateKey: privateKey,
Logger: l, Logger: l,
ArtifactsLocator: artifactsLocator, ArtifactsLocator: artifactsLocator,
}) }
return config, nil
} }
func DelayedWETH(ctx context.Context, cfg DelayedWETHConfig) error { func DelayedWETH(ctx context.Context, cfg DelayedWETHConfig) error {
......
package bootstrap
import (
"testing"
"github.com/ethereum-optimism/optimism/op-service/cliapp"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
)
func TestNewDelayedWETHConfigFromCLI(t *testing.T) {
ctx, err := parseCLIArgs(DelayedWETHFlags,
"--artifacts-locator", "tag://op-contracts/v1.6.0",
"--l1-rpc-url", "http://foo",
"--private-key", "0x123456")
require.NoError(t, err)
logger := testlog.Logger(t, log.LvlInfo)
cfg, err := NewDelayedWETHConfigFromClI(ctx, logger)
require.NoError(t, err)
require.Same(t, logger, cfg.Logger)
require.Equal(t, "op-contracts/v1.6.0", cfg.ArtifactsLocator.Tag)
require.True(t, cfg.ArtifactsLocator.IsTag())
require.Equal(t, "0x123456", cfg.PrivateKey)
}
func parseCLIArgs(flags []cli.Flag, args ...string) (*cli.Context, error) {
app := cli.NewApp()
app.Flags = cliapp.ProtectFlags(flags)
var ctx *cli.Context
app.Action = func(c *cli.Context) error {
ctx = c
return nil
}
argsWithCmd := make([]string, len(args)+1)
argsWithCmd[0] = "bootstrap"
copy(argsWithCmd[1:], args)
err := app.Run(argsWithCmd)
if err != nil {
return nil, err
}
return ctx, nil
}
...@@ -7,6 +7,9 @@ import ( ...@@ -7,6 +7,9 @@ import (
"strings" "strings"
artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env" "github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
...@@ -36,9 +39,7 @@ type DisputeGameConfig struct { ...@@ -36,9 +39,7 @@ type DisputeGameConfig struct {
privateKeyECDSA *ecdsa.PrivateKey privateKeyECDSA *ecdsa.PrivateKey
MinProposalSizeBytes uint64 Vm common.Address
ChallengePeriodSeconds uint64
MipsVersion uint64
GameKind string GameKind string
GameType uint32 GameType uint32
AbsolutePrestate common.Hash AbsolutePrestate common.Hash
...@@ -84,22 +85,44 @@ func DisputeGameCLI(cliCtx *cli.Context) error { ...@@ -84,22 +85,44 @@ func DisputeGameCLI(cliCtx *cli.Context) error {
l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg)
oplog.SetGlobalLogHandler(l.Handler()) oplog.SetGlobalLogHandler(l.Handler())
cfg, err := NewDisputeGameConfigFromCLI(cliCtx, l)
if err != nil {
return err
}
ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)
return DisputeGame(ctx, cfg)
}
func NewDisputeGameConfigFromCLI(cliCtx *cli.Context, l log.Logger) (DisputeGameConfig, error) {
l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName)
privateKey := cliCtx.String(deployer.PrivateKeyFlagName) privateKey := cliCtx.String(deployer.PrivateKeyFlagName)
artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName) artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName)
artifactsLocator := new(artifacts2.Locator) artifactsLocator := new(artifacts2.Locator)
if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil {
return fmt.Errorf("failed to parse artifacts URL: %w", err) return DisputeGameConfig{}, fmt.Errorf("failed to parse artifacts URL: %w", err)
} }
ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context) cfg := DisputeGameConfig{
return DisputeGame(ctx, DisputeGameConfig{
L1RPCUrl: l1RPCUrl, L1RPCUrl: l1RPCUrl,
PrivateKey: privateKey, PrivateKey: privateKey,
Logger: l, Logger: l,
ArtifactsLocator: artifactsLocator, ArtifactsLocator: artifactsLocator,
})
Vm: common.HexToAddress(cliCtx.String(VmFlagName)),
GameKind: cliCtx.String(GameKindFlagName),
GameType: uint32(cliCtx.Uint64(GameTypeFlagName)),
AbsolutePrestate: common.HexToHash(cliCtx.String(AbsolutePrestateFlagName)),
MaxGameDepth: cliCtx.Uint64(MaxGameDepthFlagName),
SplitDepth: cliCtx.Uint64(SplitDepthFlagName),
ClockExtension: cliCtx.Uint64(ClockExtensionFlagName),
MaxClockDuration: cliCtx.Uint64(MaxClockDurationFlagName),
DelayedWethProxy: common.HexToAddress(cliCtx.String(DelayedWethProxyFlagName)),
AnchorStateRegistryProxy: common.HexToAddress(cliCtx.String(AnchorStateRegistryProxyFlagName)),
L2ChainId: cliCtx.Uint64(L2ChainIdFlagName),
Proposer: common.HexToAddress(cliCtx.String(ProposerFlagName)),
Challenger: common.HexToAddress(cliCtx.String(ChallengerFlagName)),
}
return cfg, nil
} }
func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error { func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error {
...@@ -175,6 +198,25 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error { ...@@ -175,6 +198,25 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error {
release = "dev" release = "dev"
} }
// We need to etch the VM and PreimageOracle addresses so that they have nonzero code
// and the checks in the FaultDisputeGame constructor pass.
oracleAddr, err := loadOracleAddr(ctx, l1Client, cfg.Vm)
if err != nil {
return err
}
addresses := []common.Address{
cfg.Vm,
oracleAddr,
}
for _, addr := range addresses {
code, err := l1Client.CodeAt(ctx, addr, nil)
if err != nil {
return fmt.Errorf("failed to get code for %v: %w", addr, err)
}
host.ImportAccount(addr, types.Account{
Code: code,
})
}
lgr.Info("deploying dispute game", "release", release) lgr.Info("deploying dispute game", "release", release)
dgo, err := opcm.DeployDisputeGame( dgo, err := opcm.DeployDisputeGame(
...@@ -182,9 +224,7 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error { ...@@ -182,9 +224,7 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error {
opcm.DeployDisputeGameInput{ opcm.DeployDisputeGameInput{
Release: release, Release: release,
StandardVersionsToml: standardVersionsTOML, StandardVersionsToml: standardVersionsTOML,
MipsVersion: cfg.MipsVersion, VmAddress: cfg.Vm,
MinProposalSizeBytes: cfg.MinProposalSizeBytes,
ChallengePeriodSeconds: cfg.ChallengePeriodSeconds,
GameKind: cfg.GameKind, GameKind: cfg.GameKind,
GameType: cfg.GameType, GameType: cfg.GameType,
AbsolutePrestate: cfg.AbsolutePrestate, AbsolutePrestate: cfg.AbsolutePrestate,
...@@ -214,3 +254,15 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error { ...@@ -214,3 +254,15 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error {
} }
return nil return nil
} }
func loadOracleAddr(ctx context.Context, l1Client *ethclient.Client, vmAddr common.Address) (common.Address, error) {
callData, err := snapshots.LoadMIPSABI().Pack("oracle")
if err != nil {
return common.Address{}, fmt.Errorf("failed to create vm.oracle() calldata: %w", err)
}
result, err := l1Client.CallContract(ctx, ethereum.CallMsg{Data: callData, To: &vmAddr}, nil)
if err != nil {
return common.Address{}, fmt.Errorf("failed to call vm.oracle(): %w", err)
}
return common.BytesToAddress(result), nil
}
package bootstrap
import (
"reflect"
"testing"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"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 TestNewDisputeGameConfigFromCLI(t *testing.T) {
ctx, err := parseCLIArgs(DisputeGameFlags,
"--artifacts-locator", "tag://op-contracts/v1.6.0",
"--l1-rpc-url", "http://foo",
"--private-key", "0x123456",
"--game-type", "2",
"--delayed-weth-proxy", common.Address{0xaa}.Hex(),
"--anchor-state-registry-proxy", common.Address{0xbb}.Hex(),
"--l2-chain-id", "901",
"--proposer", common.Address{0xcc}.Hex(),
"--challenger", common.Address{0xdd}.Hex(),
"--vm", common.Address{0xee}.Hex(),
)
require.NoError(t, err)
logger := testlog.Logger(t, log.LvlInfo)
cfg, err := NewDisputeGameConfigFromCLI(ctx, logger)
require.NoError(t, err)
require.Same(t, logger, cfg.Logger)
require.Equal(t, "op-contracts/v1.6.0", cfg.ArtifactsLocator.Tag)
require.True(t, cfg.ArtifactsLocator.IsTag())
require.Equal(t, "0x123456", cfg.PrivateKey)
require.Equal(t, "FaultDisputeGame", cfg.GameKind)
require.Equal(t, uint32(2), cfg.GameType)
require.Equal(t, standard.DisputeAbsolutePrestate, cfg.AbsolutePrestate)
require.Equal(t, standard.DisputeMaxGameDepth, cfg.MaxGameDepth)
require.Equal(t, standard.DisputeSplitDepth, cfg.SplitDepth)
require.Equal(t, standard.DisputeClockExtension, cfg.ClockExtension)
require.Equal(t, standard.DisputeMaxClockDuration, cfg.MaxClockDuration)
require.Equal(t, common.Address{0xaa}, cfg.DelayedWethProxy)
require.Equal(t, common.Address{0xbb}, cfg.AnchorStateRegistryProxy)
require.Equal(t, common.Address{0xcc}, cfg.Proposer)
require.Equal(t, common.Address{0xdd}, cfg.Challenger)
require.Equal(t, common.Address{0xee}, cfg.Vm)
require.Equal(t, uint64(901), cfg.L2ChainId)
// Check all fields are set to ensure any newly added fields don't get missed.
cfgRef := reflect.ValueOf(cfg)
cfgType := reflect.TypeOf(cfg)
var unsetFields []string
for i := 0; i < cfgRef.NumField(); i++ {
field := cfgType.Field(i)
if field.Type == reflect.TypeOf(cfg.privateKeyECDSA) {
// privateKeyECDSA is only set when Check() is called so skip it.
continue
}
if cfgRef.Field(i).IsZero() {
unsetFields = append(unsetFields, field.Name)
}
}
require.Empty(t, unsetFields, "Found unset fields in config")
}
...@@ -16,6 +16,7 @@ const ( ...@@ -16,6 +16,7 @@ const (
ProofMaturityDelaySecondsFlagName = "proof-maturity-delay-seconds" ProofMaturityDelaySecondsFlagName = "proof-maturity-delay-seconds"
DisputeGameFinalityDelaySecondsFlagName = "dispute-game-finality-delay-seconds" DisputeGameFinalityDelaySecondsFlagName = "dispute-game-finality-delay-seconds"
MIPSVersionFlagName = "mips-version" MIPSVersionFlagName = "mips-version"
VmFlagName = "vm"
GameKindFlagName = "game-kind" GameKindFlagName = "game-kind"
GameTypeFlagName = "game-type" GameTypeFlagName = "game-type"
AbsolutePrestateFlagName = "absolute-prestate" AbsolutePrestateFlagName = "absolute-prestate"
...@@ -73,6 +74,11 @@ var ( ...@@ -73,6 +74,11 @@ var (
EnvVars: deployer.PrefixEnvVar("MIPS_VERSION"), EnvVars: deployer.PrefixEnvVar("MIPS_VERSION"),
Value: standard.MIPSVersion, Value: standard.MIPSVersion,
} }
VmFlag = &cli.StringFlag{
Name: VmFlagName,
Usage: "VM contract address.",
EnvVars: deployer.PrefixEnvVar("VM"),
}
GameKindFlag = &cli.StringFlag{ GameKindFlag = &cli.StringFlag{
Name: GameKindFlagName, Name: GameKindFlagName,
Usage: "Game kind (FaultDisputeGame or PermissionedDisputeGame).", Usage: "Game kind (FaultDisputeGame or PermissionedDisputeGame).",
...@@ -173,7 +179,7 @@ var DisputeGameFlags = []cli.Flag{ ...@@ -173,7 +179,7 @@ var DisputeGameFlags = []cli.Flag{
ArtifactsLocatorFlag, ArtifactsLocatorFlag,
MinProposalSizeBytesFlag, MinProposalSizeBytesFlag,
ChallengePeriodSecondsFlag, ChallengePeriodSecondsFlag,
MIPSVersionFlag, VmFlag,
GameKindFlag, GameKindFlag,
GameTypeFlag, GameTypeFlag,
AbsolutePrestateFlag, AbsolutePrestateFlag,
......
...@@ -11,9 +11,7 @@ import ( ...@@ -11,9 +11,7 @@ import (
type DeployDisputeGameInput struct { type DeployDisputeGameInput struct {
Release string Release string
StandardVersionsToml string StandardVersionsToml string
MipsVersion uint64 VmAddress common.Address
MinProposalSizeBytes uint64
ChallengePeriodSeconds uint64
GameKind string GameKind string
GameType uint32 GameType uint32
AbsolutePrestate common.Hash AbsolutePrestate common.Hash
...@@ -33,9 +31,7 @@ func (input *DeployDisputeGameInput) InputSet() bool { ...@@ -33,9 +31,7 @@ func (input *DeployDisputeGameInput) InputSet() bool {
} }
type DeployDisputeGameOutput struct { type DeployDisputeGameOutput struct {
DisputeGameImpl common.Address DisputeGameImpl common.Address
MipsSingleton common.Address
PreimageOracleSingleton common.Address
} }
func (output *DeployDisputeGameOutput) CheckOutput(input common.Address) error { func (output *DeployDisputeGameOutput) CheckOutput(input common.Address) error {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment