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 (
github.com/crate-crypto/go-kzg-4844 v0.7.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/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/fsnotify/fsnotify v1.7.0
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
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/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-20240522134500-19555bdbdc95/go.mod h1:7xh2awFQqsiZxFrHKTgEd+InVfDRrkKVUIuK8SAFHp0=
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-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/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
......
......@@ -41,7 +41,7 @@ func CreateGame(ctx *cli.Context) error {
traceType := ctx.Uint64(TraceTypeFlag.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) {
return contracts.NewDisputeGameFactoryContract(metricer, address, caller), nil
})
......@@ -61,6 +61,7 @@ func CreateGame(ctx *cli.Context) error {
func createGameFlags() []cli.Flag {
cliFlags := []cli.Flag{
flags.L1EthRpcFlag,
flags.NetworkFlag,
flags.FactoryAddressFlag,
TraceTypeFlag,
OutputRootFlag,
......
......@@ -49,7 +49,7 @@ func ListGames(ctx *cli.Context) error {
if rpcUrl == "" {
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 {
return err
}
......@@ -171,6 +171,7 @@ func listGamesFlags() []cli.Flag {
SortByFlag,
SortOrderFlag,
flags.L1EthRpcFlag,
flags.NetworkFlag,
flags.FactoryAddressFlag,
flags.GameWindowFlag,
}
......
......@@ -7,6 +7,7 @@ import (
"testing"
"time"
"github.com/ethereum-optimism/superchain-registry/superchain"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
......@@ -144,8 +145,8 @@ func TestMultipleTraceTypes(t *testing.T) {
}
func TestGameFactoryAddress(t *testing.T) {
t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag game-factory-address is required", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-factory-address"))
t.Run("RequiredWhenNetworkNotSupplied", func(t *testing.T) {
verifyArgsInvalid(t, "flag game-factory-address or network is required", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-factory-address"))
})
t.Run("Valid", func(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) {
t.Run("Optional", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist"))
......
......@@ -46,7 +46,7 @@ func Move(ctx *cli.Context) error {
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 {
return fmt.Errorf("failed to create dispute game bindings: %w", err)
}
......
......@@ -12,7 +12,7 @@ import (
)
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 {
return fmt.Errorf("failed to create dispute game bindings: %w", err)
}
......
......@@ -26,7 +26,7 @@ func ResolveClaim(ctx *cli.Context) error {
}
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 {
return fmt.Errorf("failed to create dispute game bindings: %w", err)
}
......
......@@ -17,15 +17,25 @@ import (
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.
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
caller, txMgr, err := newClientsFromCLI(ctx)
if err != nil {
return contract, nil, err
}
created, err := newContractFromCLI(ctx, flagName, caller, creator)
created, err := newContractFromCLI(ctx, getAddr, caller, creator)
if err != nil {
return contract, nil, err
}
......@@ -34,9 +44,9 @@ func NewContractWithTxMgr[T any](ctx *cli.Context, flagName string, creator Cont
}
// 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
gameAddr, err := opservice.ParseAddress(ctx.String(flagName))
gameAddr, err := getAddr(ctx)
if err != nil {
return contract, err
}
......
......@@ -7,6 +7,8 @@ import (
"slices"
"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/log"
"github.com/urfave/cli/v2"
......@@ -44,6 +46,7 @@ var (
Usage: "HTTP provider URL for the rollup node",
EnvVars: prefixEnvVars("ROLLUP_RPC"),
}
NetworkFlag = flags.CLINetworkFlag(EnvVarPrefix, "")
FactoryAddressFlag = &cli.StringFlag{
Name: "game-factory-address",
Usage: "Address of the fault game factory contract.",
......@@ -225,7 +228,6 @@ var (
// requiredFlags are checked by [CheckRequired]
var requiredFlags = []cli.Flag{
L1EthRpcFlag,
FactoryAddressFlag,
DatadirFlag,
RollupRpcFlag,
L1BeaconFlag,
......@@ -233,6 +235,8 @@ var requiredFlags = []cli.Flag{
// optionalFlags is a list of unchecked cli flags
var optionalFlags = []cli.Flag{
NetworkFlag,
FactoryAddressFlag,
TraceTypeFlag,
MaxConcurrencyFlag,
L2EthRpcFlag,
......@@ -379,6 +383,39 @@ func getL2Rpc(ctx *cli.Context, logger log.Logger) (string, error) {
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.
func NewConfigFromCLI(ctx *cli.Context, logger log.Logger) (*config.Config, error) {
traceTypes, err := parseTraceTypes(ctx)
......@@ -388,7 +425,7 @@ func NewConfigFromCLI(ctx *cli.Context, logger log.Logger) (*config.Config, erro
if err := CheckRequired(ctx, traceTypes); err != nil {
return nil, err
}
gameFactoryAddress, err := opservice.ParseAddress(ctx.String(FactoryAddressFlag.Name))
gameFactoryAddress, err := FactoryAddress(ctx)
if err != nil {
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