Commit f41e8f1e authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

challenger: Add --network option (#10711)

Loads the dispute game factory address from the superchain registry.
parent e7d447e3
...@@ -13,7 +13,7 @@ require ( ...@@ -13,7 +13,7 @@ require (
github.com/crate-crypto/go-kzg-4844 v0.7.0 github.com/crate-crypto/go-kzg-4844 v0.7.0
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240522134500-19555bdbdc95 github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240601004730-a4a101b1e535
github.com/ethereum/go-ethereum v1.13.15 github.com/ethereum/go-ethereum v1.13.15
github.com/fsnotify/fsnotify v1.7.0 github.com/fsnotify/fsnotify v1.7.0
github.com/go-chi/chi/v5 v5.0.12 github.com/go-chi/chi/v5 v5.0.12
......
...@@ -177,8 +177,8 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z ...@@ -177,8 +177,8 @@ github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v1.101315.1 h1:GhHlJ60h652XbRkp/MyWP355y+imNWjPm7hWlnG6+Fc= github.com/ethereum-optimism/op-geth v1.101315.1 h1:GhHlJ60h652XbRkp/MyWP355y+imNWjPm7hWlnG6+Fc=
github.com/ethereum-optimism/op-geth v1.101315.1/go.mod h1:8tQ6r0e1NNJbSVHzYKafQqf62gV9BzZR+SKkXRckjLM= github.com/ethereum-optimism/op-geth v1.101315.1/go.mod h1:8tQ6r0e1NNJbSVHzYKafQqf62gV9BzZR+SKkXRckjLM=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240522134500-19555bdbdc95 h1:GjXKQg6u6WkEIcY0dvW2IKhMRY8cVjwdw+rNKhduAo8= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240601004730-a4a101b1e535 h1:mHHIt9cjx02ono5ySr6gM+A6QGEMNcMVFByd6z962HM=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240522134500-19555bdbdc95/go.mod h1:7xh2awFQqsiZxFrHKTgEd+InVfDRrkKVUIuK8SAFHp0= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240601004730-a4a101b1e535/go.mod h1:7xh2awFQqsiZxFrHKTgEd+InVfDRrkKVUIuK8SAFHp0=
github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY=
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
......
...@@ -41,7 +41,7 @@ func CreateGame(ctx *cli.Context) error { ...@@ -41,7 +41,7 @@ func CreateGame(ctx *cli.Context) error {
traceType := ctx.Uint64(TraceTypeFlag.Name) traceType := ctx.Uint64(TraceTypeFlag.Name)
l2BlockNum := ctx.Uint64(L2BlockNumFlag.Name) l2BlockNum := ctx.Uint64(L2BlockNumFlag.Name)
contract, txMgr, err := NewContractWithTxMgr[*contracts.DisputeGameFactoryContract](ctx, flags.FactoryAddressFlag.Name, contract, txMgr, err := NewContractWithTxMgr[*contracts.DisputeGameFactoryContract](ctx, flags.FactoryAddress,
func(ctx context.Context, metricer contractMetrics.ContractMetricer, address common.Address, caller *batching.MultiCaller) (*contracts.DisputeGameFactoryContract, error) { func(ctx context.Context, metricer contractMetrics.ContractMetricer, address common.Address, caller *batching.MultiCaller) (*contracts.DisputeGameFactoryContract, error) {
return contracts.NewDisputeGameFactoryContract(metricer, address, caller), nil return contracts.NewDisputeGameFactoryContract(metricer, address, caller), nil
}) })
...@@ -61,6 +61,7 @@ func CreateGame(ctx *cli.Context) error { ...@@ -61,6 +61,7 @@ func CreateGame(ctx *cli.Context) error {
func createGameFlags() []cli.Flag { func createGameFlags() []cli.Flag {
cliFlags := []cli.Flag{ cliFlags := []cli.Flag{
flags.L1EthRpcFlag, flags.L1EthRpcFlag,
flags.NetworkFlag,
flags.FactoryAddressFlag, flags.FactoryAddressFlag,
TraceTypeFlag, TraceTypeFlag,
OutputRootFlag, OutputRootFlag,
......
...@@ -49,7 +49,7 @@ func ListGames(ctx *cli.Context) error { ...@@ -49,7 +49,7 @@ func ListGames(ctx *cli.Context) error {
if rpcUrl == "" { if rpcUrl == "" {
return fmt.Errorf("missing %v", flags.L1EthRpcFlag.Name) return fmt.Errorf("missing %v", flags.L1EthRpcFlag.Name)
} }
factoryAddr, err := opservice.ParseAddress(ctx.String(flags.FactoryAddressFlag.Name)) factoryAddr, err := flags.FactoryAddress(ctx)
if err != nil { if err != nil {
return err return err
} }
...@@ -171,6 +171,7 @@ func listGamesFlags() []cli.Flag { ...@@ -171,6 +171,7 @@ func listGamesFlags() []cli.Flag {
SortByFlag, SortByFlag,
SortOrderFlag, SortOrderFlag,
flags.L1EthRpcFlag, flags.L1EthRpcFlag,
flags.NetworkFlag,
flags.FactoryAddressFlag, flags.FactoryAddressFlag,
flags.GameWindowFlag, flags.GameWindowFlag,
} }
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/superchain-registry/superchain"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -144,8 +145,8 @@ func TestMultipleTraceTypes(t *testing.T) { ...@@ -144,8 +145,8 @@ func TestMultipleTraceTypes(t *testing.T) {
} }
func TestGameFactoryAddress(t *testing.T) { func TestGameFactoryAddress(t *testing.T) {
t.Run("Required", func(t *testing.T) { t.Run("RequiredWhenNetworkNotSupplied", func(t *testing.T) {
verifyArgsInvalid(t, "flag game-factory-address is required", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-factory-address")) verifyArgsInvalid(t, "flag game-factory-address or network is required", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-factory-address"))
}) })
t.Run("Valid", func(t *testing.T) { t.Run("Valid", func(t *testing.T) {
...@@ -159,6 +160,18 @@ func TestGameFactoryAddress(t *testing.T) { ...@@ -159,6 +160,18 @@ func TestGameFactoryAddress(t *testing.T) {
}) })
} }
func TestNetwork(t *testing.T) {
t.Run("Valid", func(t *testing.T) {
opSepoliaChainId := uint64(11155420)
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-factory-address", "--network=op-sepolia"))
require.EqualValues(t, superchain.Addresses[opSepoliaChainId].DisputeGameFactoryProxy, cfg.GameFactoryAddress)
})
t.Run("UnknownNetwork", func(t *testing.T) {
verifyArgsInvalid(t, "unknown chain: not-a-network", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-factory-address", "--network=not-a-network"))
})
}
func TestGameAllowlist(t *testing.T) { func TestGameAllowlist(t *testing.T) {
t.Run("Optional", func(t *testing.T) { t.Run("Optional", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist")) cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist"))
......
...@@ -46,7 +46,7 @@ func Move(ctx *cli.Context) error { ...@@ -46,7 +46,7 @@ func Move(ctx *cli.Context) error {
return fmt.Errorf("both attack and defense flags cannot be set") return fmt.Errorf("both attack and defense flags cannot be set")
} }
contract, txMgr, err := NewContractWithTxMgr[contracts.FaultDisputeGameContract](ctx, GameAddressFlag.Name, contracts.NewFaultDisputeGameContract) contract, txMgr, err := NewContractWithTxMgr[contracts.FaultDisputeGameContract](ctx, AddrFromFlag(GameAddressFlag.Name), contracts.NewFaultDisputeGameContract)
if err != nil { if err != nil {
return fmt.Errorf("failed to create dispute game bindings: %w", err) return fmt.Errorf("failed to create dispute game bindings: %w", err)
} }
......
...@@ -12,7 +12,7 @@ import ( ...@@ -12,7 +12,7 @@ import (
) )
func Resolve(ctx *cli.Context) error { func Resolve(ctx *cli.Context) error {
contract, txMgr, err := NewContractWithTxMgr[contracts.FaultDisputeGameContract](ctx, GameAddressFlag.Name, contracts.NewFaultDisputeGameContract) contract, txMgr, err := NewContractWithTxMgr[contracts.FaultDisputeGameContract](ctx, AddrFromFlag(GameAddressFlag.Name), contracts.NewFaultDisputeGameContract)
if err != nil { if err != nil {
return fmt.Errorf("failed to create dispute game bindings: %w", err) return fmt.Errorf("failed to create dispute game bindings: %w", err)
} }
......
...@@ -26,7 +26,7 @@ func ResolveClaim(ctx *cli.Context) error { ...@@ -26,7 +26,7 @@ func ResolveClaim(ctx *cli.Context) error {
} }
idx := ctx.Uint64(ClaimIdxFlag.Name) idx := ctx.Uint64(ClaimIdxFlag.Name)
contract, txMgr, err := NewContractWithTxMgr[contracts.FaultDisputeGameContract](ctx, GameAddressFlag.Name, contracts.NewFaultDisputeGameContract) contract, txMgr, err := NewContractWithTxMgr[contracts.FaultDisputeGameContract](ctx, AddrFromFlag(GameAddressFlag.Name), contracts.NewFaultDisputeGameContract)
if err != nil { if err != nil {
return fmt.Errorf("failed to create dispute game bindings: %w", err) return fmt.Errorf("failed to create dispute game bindings: %w", err)
} }
......
...@@ -17,15 +17,25 @@ import ( ...@@ -17,15 +17,25 @@ import (
type ContractCreator[T any] func(context.Context, contractMetrics.ContractMetricer, common.Address, *batching.MultiCaller) (T, error) type ContractCreator[T any] func(context.Context, contractMetrics.ContractMetricer, common.Address, *batching.MultiCaller) (T, error)
func AddrFromFlag(flagName string) func(ctx *cli.Context) (common.Address, error) {
return func(ctx *cli.Context) (common.Address, error) {
gameAddr, err := opservice.ParseAddress(ctx.String(flagName))
if err != nil {
return common.Address{}, err
}
return gameAddr, nil
}
}
// NewContractWithTxMgr creates a new contract and a transaction manager. // NewContractWithTxMgr creates a new contract and a transaction manager.
func NewContractWithTxMgr[T any](ctx *cli.Context, flagName string, creator ContractCreator[T]) (T, txmgr.TxManager, error) { func NewContractWithTxMgr[T any](ctx *cli.Context, getAddr func(ctx *cli.Context) (common.Address, error), creator ContractCreator[T]) (T, txmgr.TxManager, error) {
var contract T var contract T
caller, txMgr, err := newClientsFromCLI(ctx) caller, txMgr, err := newClientsFromCLI(ctx)
if err != nil { if err != nil {
return contract, nil, err return contract, nil, err
} }
created, err := newContractFromCLI(ctx, flagName, caller, creator) created, err := newContractFromCLI(ctx, getAddr, caller, creator)
if err != nil { if err != nil {
return contract, nil, err return contract, nil, err
} }
...@@ -34,9 +44,9 @@ func NewContractWithTxMgr[T any](ctx *cli.Context, flagName string, creator Cont ...@@ -34,9 +44,9 @@ func NewContractWithTxMgr[T any](ctx *cli.Context, flagName string, creator Cont
} }
// newContractFromCLI creates a new contract from the CLI context. // newContractFromCLI creates a new contract from the CLI context.
func newContractFromCLI[T any](ctx *cli.Context, flagName string, caller *batching.MultiCaller, creator ContractCreator[T]) (T, error) { func newContractFromCLI[T any](ctx *cli.Context, getAddr func(ctx *cli.Context) (common.Address, error), caller *batching.MultiCaller, creator ContractCreator[T]) (T, error) {
var contract T var contract T
gameAddr, err := opservice.ParseAddress(ctx.String(flagName)) gameAddr, err := getAddr(ctx)
if err != nil { if err != nil {
return contract, err return contract, err
} }
......
...@@ -7,6 +7,8 @@ import ( ...@@ -7,6 +7,8 @@ import (
"slices" "slices"
"strings" "strings"
"github.com/ethereum-optimism/optimism/op-service/flags"
"github.com/ethereum-optimism/superchain-registry/superchain"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
...@@ -44,6 +46,7 @@ var ( ...@@ -44,6 +46,7 @@ var (
Usage: "HTTP provider URL for the rollup node", Usage: "HTTP provider URL for the rollup node",
EnvVars: prefixEnvVars("ROLLUP_RPC"), EnvVars: prefixEnvVars("ROLLUP_RPC"),
} }
NetworkFlag = flags.CLINetworkFlag(EnvVarPrefix, "")
FactoryAddressFlag = &cli.StringFlag{ FactoryAddressFlag = &cli.StringFlag{
Name: "game-factory-address", Name: "game-factory-address",
Usage: "Address of the fault game factory contract.", Usage: "Address of the fault game factory contract.",
...@@ -225,7 +228,6 @@ var ( ...@@ -225,7 +228,6 @@ var (
// requiredFlags are checked by [CheckRequired] // requiredFlags are checked by [CheckRequired]
var requiredFlags = []cli.Flag{ var requiredFlags = []cli.Flag{
L1EthRpcFlag, L1EthRpcFlag,
FactoryAddressFlag,
DatadirFlag, DatadirFlag,
RollupRpcFlag, RollupRpcFlag,
L1BeaconFlag, L1BeaconFlag,
...@@ -233,6 +235,8 @@ var requiredFlags = []cli.Flag{ ...@@ -233,6 +235,8 @@ var requiredFlags = []cli.Flag{
// optionalFlags is a list of unchecked cli flags // optionalFlags is a list of unchecked cli flags
var optionalFlags = []cli.Flag{ var optionalFlags = []cli.Flag{
NetworkFlag,
FactoryAddressFlag,
TraceTypeFlag, TraceTypeFlag,
MaxConcurrencyFlag, MaxConcurrencyFlag,
L2EthRpcFlag, L2EthRpcFlag,
...@@ -379,6 +383,39 @@ func getL2Rpc(ctx *cli.Context, logger log.Logger) (string, error) { ...@@ -379,6 +383,39 @@ func getL2Rpc(ctx *cli.Context, logger log.Logger) (string, error) {
return l2Rpc, nil return l2Rpc, nil
} }
func FactoryAddress(ctx *cli.Context) (common.Address, error) {
if ctx.IsSet(FactoryAddressFlag.Name) && ctx.IsSet(flags.NetworkFlagName) {
return common.Address{}, fmt.Errorf("flag %v and %v must not both be set", FactoryAddressFlag.Name, flags.NetworkFlagName)
}
if ctx.IsSet(FactoryAddressFlag.Name) {
gameFactoryAddress, err := opservice.ParseAddress(ctx.String(FactoryAddressFlag.Name))
if err != nil {
return common.Address{}, err
}
return gameFactoryAddress, nil
}
if ctx.IsSet(flags.NetworkFlagName) {
chainName := ctx.String(flags.NetworkFlagName)
chainCfg := chaincfg.ChainByName(chainName)
if chainCfg == nil {
var opts []string
for _, cfg := range superchain.OPChains {
opts = append(opts, cfg.Chain+"-"+cfg.Superchain)
}
return common.Address{}, fmt.Errorf("unknown chain: %v (Valid options: %v)", chainName, strings.Join(opts, ", "))
}
addrs, ok := superchain.Addresses[chainCfg.ChainID]
if !ok {
return common.Address{}, fmt.Errorf("no addresses available for chain %v", chainName)
}
if addrs.DisputeGameFactoryProxy == (superchain.Address{}) {
return common.Address{}, fmt.Errorf("dispute factory proxy not available for chain %v", chainName)
}
return common.Address(addrs.DisputeGameFactoryProxy), nil
}
return common.Address{}, fmt.Errorf("flag %v or %v is required", FactoryAddressFlag.Name, flags.NetworkFlagName)
}
// NewConfigFromCLI parses the Config from the provided flags or environment variables. // NewConfigFromCLI parses the Config from the provided flags or environment variables.
func NewConfigFromCLI(ctx *cli.Context, logger log.Logger) (*config.Config, error) { func NewConfigFromCLI(ctx *cli.Context, logger log.Logger) (*config.Config, error) {
traceTypes, err := parseTraceTypes(ctx) traceTypes, err := parseTraceTypes(ctx)
...@@ -388,7 +425,7 @@ func NewConfigFromCLI(ctx *cli.Context, logger log.Logger) (*config.Config, erro ...@@ -388,7 +425,7 @@ func NewConfigFromCLI(ctx *cli.Context, logger log.Logger) (*config.Config, erro
if err := CheckRequired(ctx, traceTypes); err != nil { if err := CheckRequired(ctx, traceTypes); err != nil {
return nil, err return nil, err
} }
gameFactoryAddress, err := opservice.ParseAddress(ctx.String(FactoryAddressFlag.Name)) gameFactoryAddress, err := FactoryAddress(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
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