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 {
l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg)
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)
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)
return DelayedWETHConfig{}, fmt.Errorf("failed to parse artifacts URL: %w", err)
}
ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)
return DelayedWETH(ctx, DelayedWETHConfig{
config := DelayedWETHConfig{
L1RPCUrl: l1RPCUrl,
PrivateKey: privateKey,
Logger: l,
ArtifactsLocator: artifactsLocator,
})
}
return config, nil
}
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 (
"strings"
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"
......@@ -36,9 +39,7 @@ type DisputeGameConfig struct {
privateKeyECDSA *ecdsa.PrivateKey
MinProposalSizeBytes uint64
ChallengePeriodSeconds uint64
MipsVersion uint64
Vm common.Address
GameKind string
GameType uint32
AbsolutePrestate common.Hash
......@@ -84,22 +85,44 @@ func DisputeGameCLI(cliCtx *cli.Context) error {
l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg)
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)
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)
return DisputeGameConfig{}, fmt.Errorf("failed to parse artifacts URL: %w", err)
}
ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)
return DisputeGame(ctx, DisputeGameConfig{
cfg := DisputeGameConfig{
L1RPCUrl: l1RPCUrl,
PrivateKey: privateKey,
Logger: l,
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 {
......@@ -175,6 +198,25 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error {
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)
dgo, err := opcm.DeployDisputeGame(
......@@ -182,9 +224,7 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error {
opcm.DeployDisputeGameInput{
Release: release,
StandardVersionsToml: standardVersionsTOML,
MipsVersion: cfg.MipsVersion,
MinProposalSizeBytes: cfg.MinProposalSizeBytes,
ChallengePeriodSeconds: cfg.ChallengePeriodSeconds,
VmAddress: cfg.Vm,
GameKind: cfg.GameKind,
GameType: cfg.GameType,
AbsolutePrestate: cfg.AbsolutePrestate,
......@@ -214,3 +254,15 @@ func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error {
}
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 (
ProofMaturityDelaySecondsFlagName = "proof-maturity-delay-seconds"
DisputeGameFinalityDelaySecondsFlagName = "dispute-game-finality-delay-seconds"
MIPSVersionFlagName = "mips-version"
VmFlagName = "vm"
GameKindFlagName = "game-kind"
GameTypeFlagName = "game-type"
AbsolutePrestateFlagName = "absolute-prestate"
......@@ -73,6 +74,11 @@ var (
EnvVars: deployer.PrefixEnvVar("MIPS_VERSION"),
Value: standard.MIPSVersion,
}
VmFlag = &cli.StringFlag{
Name: VmFlagName,
Usage: "VM contract address.",
EnvVars: deployer.PrefixEnvVar("VM"),
}
GameKindFlag = &cli.StringFlag{
Name: GameKindFlagName,
Usage: "Game kind (FaultDisputeGame or PermissionedDisputeGame).",
......@@ -173,7 +179,7 @@ var DisputeGameFlags = []cli.Flag{
ArtifactsLocatorFlag,
MinProposalSizeBytesFlag,
ChallengePeriodSecondsFlag,
MIPSVersionFlag,
VmFlag,
GameKindFlag,
GameTypeFlag,
AbsolutePrestateFlag,
......
......@@ -11,9 +11,7 @@ import (
type DeployDisputeGameInput struct {
Release string
StandardVersionsToml string
MipsVersion uint64
MinProposalSizeBytes uint64
ChallengePeriodSeconds uint64
VmAddress common.Address
GameKind string
GameType uint32
AbsolutePrestate common.Hash
......@@ -33,9 +31,7 @@ func (input *DeployDisputeGameInput) InputSet() bool {
}
type DeployDisputeGameOutput struct {
DisputeGameImpl common.Address
MipsSingleton common.Address
PreimageOracleSingleton common.Address
DisputeGameImpl common.Address
}
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