diff --git a/op-challenger/cmd/main_test.go b/op-challenger/cmd/main_test.go index 529711bbf660..d471f45dc594 100644 --- a/op-challenger/cmd/main_test.go +++ b/op-challenger/cmd/main_test.go @@ -287,7 +287,7 @@ func TestAsteriscOpProgramRequiredArgs(t *testing.T) { }) t.Run("Required", func(t *testing.T) { - verifyArgsInvalid(t, "flag asterisc-prestates-url or asterisc-prestate is required", addRequiredArgsExcept(traceType, "--asterisc-prestate")) + verifyArgsInvalid(t, "flag prestates-url or asterisc-prestate is required", addRequiredArgsExcept(traceType, "--asterisc-prestate")) }) t.Run("Valid", func(t *testing.T) { @@ -296,13 +296,42 @@ func TestAsteriscOpProgramRequiredArgs(t *testing.T) { }) }) + t.Run(fmt.Sprintf("TestPrestateBaseURL-%v", traceType), func(t *testing.T) { + allPrestateOptions := []string{"--prestates-url", "--asterisc-prestates-url", "--asterisc-prestate"} + t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) { + configForArgs(t, addRequiredArgsExceptArr(types.TraceTypeAlphabet, allPrestateOptions)) + }) + + t.Run("NotRequiredIfAsteriscPrestatesBaseURLSet", func(t *testing.T) { + configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--asterisc-prestates-url=http://localhost/foo")) + }) + + t.Run("AsteriscPrestatesBaseURLTakesPrecedence", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--asterisc-prestates-url=http://localhost/foo", "--prestates-url=http://localhost/bar")) + require.Equal(t, "http://localhost/foo", cfg.AsteriscAbsolutePreStateBaseURL.String()) + }) + + t.Run("RequiredIfAsteriscPrestatesBaseURLNotSet", func(t *testing.T) { + verifyArgsInvalid(t, "flag prestates-url or asterisc-prestate is required", addRequiredArgsExceptArr(traceType, allPrestateOptions)) + }) + + t.Run("Invalid", func(t *testing.T) { + verifyArgsInvalid(t, "invalid prestates-url (:foo/bar)", addRequiredArgsExceptArr(traceType, allPrestateOptions, "--prestates-url=:foo/bar")) + }) + + t.Run("Valid", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--prestates-url=http://localhost/foo")) + require.Equal(t, "http://localhost/foo", cfg.AsteriscAbsolutePreStateBaseURL.String()) + }) + }) + t.Run(fmt.Sprintf("TestAsteriscAbsolutePrestateBaseURL-%v", traceType), func(t *testing.T) { t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) { configForArgs(t, addRequiredArgsExcept(types.TraceTypeAlphabet, "--asterisc-prestates-url")) }) t.Run("Required", func(t *testing.T) { - verifyArgsInvalid(t, "flag asterisc-prestates-url or asterisc-prestate is required", addRequiredArgsExcept(traceType, "--asterisc-prestate")) + verifyArgsInvalid(t, "flag prestates-url or asterisc-prestate is required", addRequiredArgsExcept(traceType, "--asterisc-prestate")) }) t.Run("Valid", func(t *testing.T) { @@ -335,7 +364,7 @@ func TestAsteriscKonaRequiredArgs(t *testing.T) { }) t.Run("Required", func(t *testing.T) { - verifyArgsInvalid(t, "flag asterisc-kona-prestates-url or asterisc-kona-prestate is required", addRequiredArgsExcept(traceType, "--asterisc-kona-prestate")) + verifyArgsInvalid(t, "flag prestates-url or asterisc-kona-prestate is required", addRequiredArgsExcept(traceType, "--asterisc-kona-prestate")) }) t.Run("Valid", func(t *testing.T) { @@ -350,7 +379,7 @@ func TestAsteriscKonaRequiredArgs(t *testing.T) { }) t.Run("Required", func(t *testing.T) { - verifyArgsInvalid(t, "flag asterisc-kona-prestates-url or asterisc-kona-prestate is required", addRequiredArgsExcept(traceType, "--asterisc-kona-prestate")) + verifyArgsInvalid(t, "flag prestates-url or asterisc-kona-prestate is required", addRequiredArgsExcept(traceType, "--asterisc-kona-prestate")) }) t.Run("Valid", func(t *testing.T) { @@ -358,6 +387,35 @@ func TestAsteriscKonaRequiredArgs(t *testing.T) { require.Equal(t, "http://localhost/bar", cfg.AsteriscKonaAbsolutePreStateBaseURL.String()) }) }) + + t.Run(fmt.Sprintf("TestPrestateBaseURL-%v", traceType), func(t *testing.T) { + allPrestateOptions := []string{"--prestates-url", "--asterisc-kona-prestates-url", "--asterisc-kona-prestate"} + t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) { + configForArgs(t, addRequiredArgsExceptArr(types.TraceTypeAlphabet, allPrestateOptions)) + }) + + t.Run("NotRequiredIfAsteriscKonaPrestatesBaseURLSet", func(t *testing.T) { + configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--asterisc-kona-prestates-url=http://localhost/foo")) + }) + + t.Run("AsteriscKonaPrestatesBaseURLTakesPrecedence", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--asterisc-kona-prestates-url=http://localhost/foo", "--prestates-url=http://localhost/bar")) + require.Equal(t, "http://localhost/foo", cfg.AsteriscKonaAbsolutePreStateBaseURL.String()) + }) + + t.Run("RequiredIfAsteriscKonaPrestatesBaseURLNotSet", func(t *testing.T) { + verifyArgsInvalid(t, "flag prestates-url or asterisc-kona-prestate is required", addRequiredArgsExceptArr(traceType, allPrestateOptions)) + }) + + t.Run("Invalid", func(t *testing.T) { + verifyArgsInvalid(t, "invalid prestates-url (:foo/bar)", addRequiredArgsExceptArr(traceType, allPrestateOptions, "--prestates-url=:foo/bar")) + }) + + t.Run("Valid", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--prestates-url=http://localhost/foo")) + require.Equal(t, "http://localhost/foo", cfg.AsteriscKonaAbsolutePreStateBaseURL.String()) + }) + }) } func TestAsteriscBaseRequiredArgs(t *testing.T) { @@ -579,7 +637,7 @@ func TestCannonRequiredArgs(t *testing.T) { }) t.Run("Required", func(t *testing.T) { - verifyArgsInvalid(t, "flag cannon-prestates-url or cannon-prestate is required", addRequiredArgsExcept(traceType, "--cannon-prestate")) + verifyArgsInvalid(t, "flag prestates-url or cannon-prestate is required", addRequiredArgsExcept(traceType, "--cannon-prestate")) }) t.Run("Valid", func(t *testing.T) { @@ -588,13 +646,13 @@ func TestCannonRequiredArgs(t *testing.T) { }) }) - t.Run(fmt.Sprintf("TestCannonAbsolutePrestateBaseURL-%v", traceType), func(t *testing.T) { + t.Run(fmt.Sprintf("TestCannonPrestatesBaseURL-%v", traceType), func(t *testing.T) { t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) { configForArgs(t, addRequiredArgsExcept(types.TraceTypeAlphabet, "--cannon-prestates-url")) }) t.Run("Required", func(t *testing.T) { - verifyArgsInvalid(t, "flag cannon-prestates-url or cannon-prestate is required", addRequiredArgsExcept(traceType, "--cannon-prestate")) + verifyArgsInvalid(t, "flag prestates-url or cannon-prestate is required", addRequiredArgsExcept(traceType, "--cannon-prestate")) }) t.Run("Valid", func(t *testing.T) { @@ -603,6 +661,35 @@ func TestCannonRequiredArgs(t *testing.T) { }) }) + t.Run(fmt.Sprintf("TestPrestateBaseURL-%v", traceType), func(t *testing.T) { + allPrestateOptions := []string{"--prestates-url", "--cannon-prestates-url", "--cannon-prestate"} + t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) { + configForArgs(t, addRequiredArgsExceptArr(types.TraceTypeAlphabet, allPrestateOptions)) + }) + + t.Run("NotRequiredIfCannonPrestatesBaseURLSet", func(t *testing.T) { + configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--cannon-prestates-url=http://localhost/foo")) + }) + + t.Run("CannonPrestatesBaseURLTakesPrecedence", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--cannon-prestates-url=http://localhost/foo", "--prestates-url=http://localhost/bar")) + require.Equal(t, "http://localhost/foo", cfg.CannonAbsolutePreStateBaseURL.String()) + }) + + t.Run("RequiredIfCannonPrestatesBaseURLNotSet", func(t *testing.T) { + verifyArgsInvalid(t, "flag prestates-url or cannon-prestate is required", addRequiredArgsExceptArr(traceType, allPrestateOptions)) + }) + + t.Run("Invalid", func(t *testing.T) { + verifyArgsInvalid(t, "invalid prestates-url (:foo/bar)", addRequiredArgsExceptArr(traceType, allPrestateOptions, "--prestates-url=:foo/bar")) + }) + + t.Run("Valid", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgsExceptArr(traceType, allPrestateOptions, "--prestates-url=http://localhost/foo")) + require.Equal(t, "http://localhost/foo", cfg.CannonAbsolutePreStateBaseURL.String()) + }) + }) + t.Run(fmt.Sprintf("TestL2Rpc-%v", traceType), func(t *testing.T) { t.Run("RequiredForCannonTrace", func(t *testing.T) { verifyArgsInvalid(t, "flag l2-eth-rpc is required", addRequiredArgsExcept(traceType, "--l2-eth-rpc")) @@ -889,6 +976,14 @@ func addRequiredArgsExcept(traceType types.TraceType, name string, optionalArgs return append(toArgList(req), optionalArgs...) } +func addRequiredArgsExceptArr(traceType types.TraceType, names []string, optionalArgs ...string) []string { + req := requiredArgs(traceType) + for _, name := range names { + delete(req, name) + } + return append(toArgList(req), optionalArgs...) +} + func requiredArgs(traceType types.TraceType) map[string]string { args := map[string]string{ "--l1-eth-rpc": l1EthRpc, diff --git a/op-challenger/config/config.go b/op-challenger/config/config.go index e8a245936f33..664c1bca9f1f 100644 --- a/op-challenger/config/config.go +++ b/op-challenger/config/config.go @@ -18,37 +18,46 @@ import ( ) var ( - ErrMissingTraceType = errors.New("no supported trace types specified") - ErrMissingDatadir = errors.New("missing datadir") - ErrMaxConcurrencyZero = errors.New("max concurrency must not be 0") - ErrMissingL2Rpc = errors.New("missing L2 rpc url") - ErrMissingCannonBin = errors.New("missing cannon bin") - ErrMissingCannonServer = errors.New("missing cannon server") - ErrMissingCannonAbsolutePreState = errors.New("missing cannon absolute pre-state") - ErrCannonAbsolutePreStateAndBaseURL = errors.New("only specify one of cannon absolute pre-state and cannon absolute pre-state base URL") - ErrMissingL1EthRPC = errors.New("missing l1 eth rpc url") - ErrMissingL1Beacon = errors.New("missing l1 beacon url") - ErrMissingGameFactoryAddress = errors.New("missing game factory address") - ErrMissingCannonSnapshotFreq = errors.New("missing cannon snapshot freq") - ErrMissingCannonInfoFreq = errors.New("missing cannon info freq") - ErrMissingCannonRollupConfig = errors.New("missing cannon network or rollup config path") - ErrMissingCannonL2Genesis = errors.New("missing cannon network or l2 genesis path") - ErrCannonNetworkAndRollupConfig = errors.New("only specify one of network or rollup config path") - ErrCannonNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path") - ErrCannonNetworkUnknown = errors.New("unknown cannon network") - ErrMissingRollupRpc = errors.New("missing rollup rpc url") + ErrMissingTraceType = errors.New("no supported trace types specified") + ErrMissingDatadir = errors.New("missing datadir") + ErrMaxConcurrencyZero = errors.New("max concurrency must not be 0") + ErrMissingL2Rpc = errors.New("missing L2 rpc url") + ErrMissingCannonBin = errors.New("missing cannon bin") + ErrMissingCannonServer = errors.New("missing cannon server") + ErrMissingCannonAbsolutePreState = errors.New("missing cannon absolute pre-state") + ErrMissingL1EthRPC = errors.New("missing l1 eth rpc url") + ErrMissingL1Beacon = errors.New("missing l1 beacon url") + ErrMissingGameFactoryAddress = errors.New("missing game factory address") + ErrMissingCannonSnapshotFreq = errors.New("missing cannon snapshot freq") + ErrMissingCannonInfoFreq = errors.New("missing cannon info freq") + ErrMissingCannonRollupConfig = errors.New("missing cannon network or rollup config path") + ErrMissingCannonL2Genesis = errors.New("missing cannon network or l2 genesis path") + ErrCannonNetworkAndRollupConfig = errors.New("only specify one of network or rollup config path") + ErrCannonNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path") + ErrCannonNetworkUnknown = errors.New("unknown cannon network") + ErrMissingRollupRpc = errors.New("missing rollup rpc url") - ErrMissingAsteriscBin = errors.New("missing asterisc bin") - ErrMissingAsteriscServer = errors.New("missing asterisc server") - ErrMissingAsteriscAbsolutePreState = errors.New("missing asterisc absolute pre-state") - ErrAsteriscAbsolutePreStateAndBaseURL = errors.New("only specify one of asterisc absolute pre-state and asterisc absolute pre-state base URL") - ErrMissingAsteriscSnapshotFreq = errors.New("missing asterisc snapshot freq") - ErrMissingAsteriscInfoFreq = errors.New("missing asterisc info freq") - ErrMissingAsteriscRollupConfig = errors.New("missing asterisc network or rollup config path") - ErrMissingAsteriscL2Genesis = errors.New("missing asterisc network or l2 genesis path") - ErrAsteriscNetworkAndRollupConfig = errors.New("only specify one of network or rollup config path") - ErrAsteriscNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path") - ErrAsteriscNetworkUnknown = errors.New("unknown asterisc network") + ErrMissingAsteriscBin = errors.New("missing asterisc bin") + ErrMissingAsteriscServer = errors.New("missing asterisc server") + ErrMissingAsteriscAbsolutePreState = errors.New("missing asterisc absolute pre-state") + ErrMissingAsteriscSnapshotFreq = errors.New("missing asterisc snapshot freq") + ErrMissingAsteriscInfoFreq = errors.New("missing asterisc info freq") + ErrMissingAsteriscRollupConfig = errors.New("missing asterisc network or rollup config path") + ErrMissingAsteriscL2Genesis = errors.New("missing asterisc network or l2 genesis path") + ErrAsteriscNetworkAndRollupConfig = errors.New("only specify one of network or rollup config path") + ErrAsteriscNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path") + ErrAsteriscNetworkUnknown = errors.New("unknown asterisc network") + + ErrMissingAsteriscKonaBin = errors.New("missing asterisc kona bin") + ErrMissingAsteriscKonaServer = errors.New("missing asterisc kona server") + ErrMissingAsteriscKonaAbsolutePreState = errors.New("missing asterisc kona absolute pre-state") + ErrMissingAsteriscKonaSnapshotFreq = errors.New("missing asterisc kona snapshot freq") + ErrMissingAsteriscKonaInfoFreq = errors.New("missing asterisc kona info freq") + ErrMissingAsteriscKonaRollupConfig = errors.New("missing asterisc kona network or rollup config path") + ErrMissingAsteriscKonaL2Genesis = errors.New("missing asterisc kona network or l2 genesis path") + ErrAsteriscKonaNetworkAndRollupConfig = errors.New("only specify one of network or rollup config path") + ErrAsteriscKonaNetworkAndL2Genesis = errors.New("only specify one of network or l2 genesis path") + ErrAsteriscKonaNetworkUnknown = errors.New("unknown asterisc kona network") ) const ( @@ -225,9 +234,6 @@ func (c Config) Check() error { if c.CannonAbsolutePreState == "" && c.CannonAbsolutePreStateBaseURL == nil { return ErrMissingCannonAbsolutePreState } - if c.CannonAbsolutePreState != "" && c.CannonAbsolutePreStateBaseURL != nil { - return ErrCannonAbsolutePreStateAndBaseURL - } if c.Cannon.SnapshotFreq == 0 { return ErrMissingCannonSnapshotFreq } @@ -263,9 +269,6 @@ func (c Config) Check() error { if c.AsteriscAbsolutePreState == "" && c.AsteriscAbsolutePreStateBaseURL == nil { return ErrMissingAsteriscAbsolutePreState } - if c.AsteriscAbsolutePreState != "" && c.AsteriscAbsolutePreStateBaseURL != nil { - return ErrAsteriscAbsolutePreStateAndBaseURL - } if c.Asterisc.SnapshotFreq == 0 { return ErrMissingAsteriscSnapshotFreq } @@ -273,6 +276,41 @@ func (c Config) Check() error { return ErrMissingAsteriscInfoFreq } } + if c.TraceTypeEnabled(types.TraceTypeAsteriscKona) { + if c.AsteriscKona.VmBin == "" { + return ErrMissingAsteriscKonaBin + } + if c.AsteriscKona.Server == "" { + return ErrMissingAsteriscKonaServer + } + if c.AsteriscKona.Network == "" { + if c.AsteriscKona.RollupConfigPath == "" { + return ErrMissingAsteriscKonaRollupConfig + } + if c.AsteriscKona.L2GenesisPath == "" { + return ErrMissingAsteriscKonaL2Genesis + } + } else { + if c.AsteriscKona.RollupConfigPath != "" { + return ErrAsteriscKonaNetworkAndRollupConfig + } + if c.AsteriscKona.L2GenesisPath != "" { + return ErrAsteriscKonaNetworkAndL2Genesis + } + if ch := chaincfg.ChainByName(c.AsteriscKona.Network); ch == nil { + return fmt.Errorf("%w: %v", ErrAsteriscKonaNetworkUnknown, c.AsteriscKona.Network) + } + } + if c.AsteriscKonaAbsolutePreState == "" && c.AsteriscKonaAbsolutePreStateBaseURL == nil { + return ErrMissingAsteriscKonaAbsolutePreState + } + if c.AsteriscKona.SnapshotFreq == 0 { + return ErrMissingAsteriscKonaSnapshotFreq + } + if c.AsteriscKona.InfoFreq == 0 { + return ErrMissingAsteriscKonaInfoFreq + } + } if err := c.TxMgrConfig.Check(); err != nil { return err } diff --git a/op-challenger/config/config_test.go b/op-challenger/config/config_test.go index 4181fd069bed..0d922b77fe9b 100644 --- a/op-challenger/config/config_test.go +++ b/op-challenger/config/config_test.go @@ -31,10 +31,17 @@ var ( validAsteriscNetwork = "mainnet" validAsteriscAbsolutePreState = "pre.json" validAsteriscAbsolutePreStateBaseURL, _ = url.Parse("http://localhost/bar/") + + validAsteriscKonaBin = "./bin/asterisc" + validAsteriscKonaServerBin = "./bin/kona-host" + validAsteriscKonaNetwork = "mainnet" + validAsteriscKonaAbsolutePreState = "pre.json" + validAsteriscKonaAbsolutePreStateBaseURL, _ = url.Parse("http://localhost/bar/") ) var cannonTraceTypes = []types.TraceType{types.TraceTypeCannon, types.TraceTypePermissioned} var asteriscTraceTypes = []types.TraceType{types.TraceTypeAsterisc} +var asteriscKonaTraceTypes = []types.TraceType{types.TraceTypeAsteriscKona} func applyValidConfigForCannon(cfg *Config) { cfg.Cannon.VmBin = validCannonBin @@ -50,6 +57,13 @@ func applyValidConfigForAsterisc(cfg *Config) { cfg.Asterisc.Network = validAsteriscNetwork } +func applyValidConfigForAsteriscKona(cfg *Config) { + cfg.AsteriscKona.VmBin = validAsteriscKonaBin + cfg.AsteriscKona.Server = validAsteriscKonaServerBin + cfg.AsteriscKonaAbsolutePreStateBaseURL = validAsteriscKonaAbsolutePreStateBaseURL + cfg.AsteriscKona.Network = validAsteriscKonaNetwork +} + func validConfig(traceType types.TraceType) Config { cfg := NewConfig(validGameFactoryAddress, validL1EthRpc, validL1BeaconUrl, validRollupRpc, validL2Rpc, validDatadir, traceType) if traceType == types.TraceTypeCannon || traceType == types.TraceTypePermissioned { @@ -58,6 +72,9 @@ func validConfig(traceType types.TraceType) Config { if traceType == types.TraceTypeAsterisc { applyValidConfigForAsterisc(&cfg) } + if traceType == types.TraceTypeAsteriscKona { + applyValidConfigForAsteriscKona(&cfg) + } return cfg } @@ -147,11 +164,12 @@ func TestCannonRequiredArgs(t *testing.T) { require.NoError(t, config.Check()) }) - t.Run(fmt.Sprintf("TestMustNotSupplyBothCannonAbsolutePreStateAndBaseURL-%v", traceType), func(t *testing.T) { + t.Run(fmt.Sprintf("TestAllowSupplyingBothCannonAbsolutePreStateAndBaseURL-%v", traceType), func(t *testing.T) { + // Since the prestate baseURL might be inherited from the --prestate-urls option, allow overriding it with a specific prestate config := validConfig(traceType) config.CannonAbsolutePreState = validCannonAbsolutePreState config.CannonAbsolutePreStateBaseURL = validCannonAbsolutePreStateBaseURL - require.ErrorIs(t, config.Check(), ErrCannonAbsolutePreStateAndBaseURL) + require.NoError(t, config.Check()) }) t.Run(fmt.Sprintf("TestL2RpcRequired-%v", traceType), func(t *testing.T) { @@ -258,11 +276,12 @@ func TestAsteriscRequiredArgs(t *testing.T) { require.NoError(t, config.Check()) }) - t.Run(fmt.Sprintf("TestMustNotSupplyBothAsteriscAbsolutePreStateAndBaseURL-%v", traceType), func(t *testing.T) { + t.Run(fmt.Sprintf("TestAllowSupplingBothAsteriscAbsolutePreStateAndBaseURL-%v", traceType), func(t *testing.T) { + // Since the prestate base URL might be inherited from the --prestate-urls option, allow overriding it with a specific prestate config := validConfig(traceType) config.AsteriscAbsolutePreState = validAsteriscAbsolutePreState config.AsteriscAbsolutePreStateBaseURL = validAsteriscAbsolutePreStateBaseURL - require.ErrorIs(t, config.Check(), ErrAsteriscAbsolutePreStateAndBaseURL) + require.NoError(t, config.Check()) }) t.Run(fmt.Sprintf("TestL2RpcRequired-%v", traceType), func(t *testing.T) { @@ -332,6 +351,118 @@ func TestAsteriscRequiredArgs(t *testing.T) { } } +func TestAsteriscKonaRequiredArgs(t *testing.T) { + for _, traceType := range asteriscKonaTraceTypes { + traceType := traceType + + t.Run(fmt.Sprintf("TestAsteriscKonaBinRequired-%v", traceType), func(t *testing.T) { + config := validConfig(traceType) + config.AsteriscKona.VmBin = "" + require.ErrorIs(t, config.Check(), ErrMissingAsteriscKonaBin) + }) + + t.Run(fmt.Sprintf("TestAsteriscKonaServerRequired-%v", traceType), func(t *testing.T) { + config := validConfig(traceType) + config.AsteriscKona.Server = "" + require.ErrorIs(t, config.Check(), ErrMissingAsteriscKonaServer) + }) + + t.Run(fmt.Sprintf("TestAsteriscKonaAbsolutePreStateOrBaseURLRequired-%v", traceType), func(t *testing.T) { + config := validConfig(traceType) + config.AsteriscKonaAbsolutePreState = "" + config.AsteriscKonaAbsolutePreStateBaseURL = nil + require.ErrorIs(t, config.Check(), ErrMissingAsteriscKonaAbsolutePreState) + }) + + t.Run(fmt.Sprintf("TestAsteriscKonaAbsolutePreState-%v", traceType), func(t *testing.T) { + config := validConfig(traceType) + config.AsteriscKonaAbsolutePreState = validAsteriscKonaAbsolutePreState + config.AsteriscKonaAbsolutePreStateBaseURL = nil + require.NoError(t, config.Check()) + }) + + t.Run(fmt.Sprintf("TestAsteriscKonaAbsolutePreStateBaseURL-%v", traceType), func(t *testing.T) { + config := validConfig(traceType) + config.AsteriscKonaAbsolutePreState = "" + config.AsteriscKonaAbsolutePreStateBaseURL = validAsteriscKonaAbsolutePreStateBaseURL + require.NoError(t, config.Check()) + }) + + t.Run(fmt.Sprintf("TestAllowSupplyingBothAsteriscKonaAbsolutePreStateAndBaseURL-%v", traceType), func(t *testing.T) { + // Since the prestate base URL might be inherited from the --prestate-urls option, allow overriding it with a specific prestate + config := validConfig(traceType) + config.AsteriscKonaAbsolutePreState = validAsteriscKonaAbsolutePreState + config.AsteriscKonaAbsolutePreStateBaseURL = validAsteriscKonaAbsolutePreStateBaseURL + require.NoError(t, config.Check()) + }) + + t.Run(fmt.Sprintf("TestL2RpcRequired-%v", traceType), func(t *testing.T) { + config := validConfig(traceType) + config.L2Rpc = "" + require.ErrorIs(t, config.Check(), ErrMissingL2Rpc) + }) + + t.Run(fmt.Sprintf("TestAsteriscKonaSnapshotFreq-%v", traceType), func(t *testing.T) { + t.Run("MustNotBeZero", func(t *testing.T) { + cfg := validConfig(traceType) + cfg.AsteriscKona.SnapshotFreq = 0 + require.ErrorIs(t, cfg.Check(), ErrMissingAsteriscKonaSnapshotFreq) + }) + }) + + t.Run(fmt.Sprintf("TestAsteriscKonaInfoFreq-%v", traceType), func(t *testing.T) { + t.Run("MustNotBeZero", func(t *testing.T) { + cfg := validConfig(traceType) + cfg.AsteriscKona.InfoFreq = 0 + require.ErrorIs(t, cfg.Check(), ErrMissingAsteriscKonaInfoFreq) + }) + }) + + t.Run(fmt.Sprintf("TestAsteriscKonaNetworkOrRollupConfigRequired-%v", traceType), func(t *testing.T) { + cfg := validConfig(traceType) + cfg.AsteriscKona.Network = "" + cfg.AsteriscKona.RollupConfigPath = "" + cfg.AsteriscKona.L2GenesisPath = "genesis.json" + require.ErrorIs(t, cfg.Check(), ErrMissingAsteriscKonaRollupConfig) + }) + + t.Run(fmt.Sprintf("TestAsteriscKonaNetworkOrL2GenesisRequired-%v", traceType), func(t *testing.T) { + cfg := validConfig(traceType) + cfg.AsteriscKona.Network = "" + cfg.AsteriscKona.RollupConfigPath = "foo.json" + cfg.AsteriscKona.L2GenesisPath = "" + require.ErrorIs(t, cfg.Check(), ErrMissingAsteriscKonaL2Genesis) + }) + + t.Run(fmt.Sprintf("TestMustNotSpecifyNetworkAndRollup-%v", traceType), func(t *testing.T) { + cfg := validConfig(traceType) + cfg.AsteriscKona.Network = validAsteriscKonaNetwork + cfg.AsteriscKona.RollupConfigPath = "foo.json" + cfg.AsteriscKona.L2GenesisPath = "" + require.ErrorIs(t, cfg.Check(), ErrAsteriscKonaNetworkAndRollupConfig) + }) + + t.Run(fmt.Sprintf("TestMustNotSpecifyNetworkAndL2Genesis-%v", traceType), func(t *testing.T) { + cfg := validConfig(traceType) + cfg.AsteriscKona.Network = validAsteriscKonaNetwork + cfg.AsteriscKona.RollupConfigPath = "" + cfg.AsteriscKona.L2GenesisPath = "foo.json" + require.ErrorIs(t, cfg.Check(), ErrAsteriscKonaNetworkAndL2Genesis) + }) + + t.Run(fmt.Sprintf("TestNetworkMustBeValid-%v", traceType), func(t *testing.T) { + cfg := validConfig(traceType) + cfg.AsteriscKona.Network = "unknown" + require.ErrorIs(t, cfg.Check(), ErrAsteriscKonaNetworkUnknown) + }) + + t.Run(fmt.Sprintf("TestDebugInfoDisabled-%v", traceType), func(t *testing.T) { + cfg := validConfig(traceType) + require.False(t, cfg.AsteriscKona.DebugInfo) + }) + } +} + func TestDatadirRequired(t *testing.T) { config := validConfig(types.TraceTypeAlphabet) config.Datadir = "" diff --git a/op-challenger/flags/flags.go b/op-challenger/flags/flags.go index 38e59d350cec..9e3e96407f81 100644 --- a/op-challenger/flags/flags.go +++ b/op-challenger/flags/flags.go @@ -32,6 +32,7 @@ func prefixEnvVars(name string) []string { } var ( + faultDisputeVMs = []types.TraceType{types.TraceTypeCannon, types.TraceTypeAsterisc, types.TraceTypeAsteriscKona} // Required Flags L1EthRpcFlag = &cli.StringFlag{ Name: "l1-eth-rpc", @@ -100,6 +101,15 @@ var ( Usage: "List of addresses to claim bonds for, in addition to the configured transaction sender", EnvVars: prefixEnvVars("ADDITIONAL_BOND_CLAIMANTS"), } + PreStatesURLFlag = NewVMFlag("prestates-url", EnvVarPrefix, faultDisputeVMs, func(name string, envVars []string, traceTypeInfo string) cli.Flag { + return &cli.StringFlag{ + Name: name, + Usage: "Base URL to absolute prestates to use when generating trace data. " + + "Prestates in this directory should be name as .bin.gz .json.gz or .json " + + traceTypeInfo, + EnvVars: envVars, + } + }) CannonNetworkFlag = &cli.StringFlag{ Name: "cannon-network", Usage: fmt.Sprintf("Deprecated: Use %v instead", flags.NetworkFlagName), @@ -130,12 +140,6 @@ var ( Usage: "Path to absolute prestate to use when generating trace data (cannon trace type only)", EnvVars: prefixEnvVars("CANNON_PRESTATE"), } - CannonPreStatesURLFlag = &cli.StringFlag{ - Name: "cannon-prestates-url", - Usage: "Base URL to absolute prestates to use when generating trace data. " + - "Prestates in this directory should be name as .json (cannon trace type only)", - EnvVars: prefixEnvVars("CANNON_PRESTATES_URL"), - } CannonL2Flag = &cli.StringFlag{ Name: "cannon-l2", Usage: fmt.Sprintf("Deprecated: Use %v instead", L2EthRpcFlag.Name), @@ -193,18 +197,6 @@ var ( Usage: "Path to absolute prestate to use when generating trace data (asterisc-kona trace type only)", EnvVars: prefixEnvVars("ASTERISC_KONA_PRESTATE"), } - AsteriscPreStatesURLFlag = &cli.StringFlag{ - Name: "asterisc-prestates-url", - Usage: "Base URL to absolute prestates to use when generating trace data. " + - "Prestates in this directory should be name as .json (asterisc trace type only)", - EnvVars: prefixEnvVars("ASTERISC_PRESTATES_URL"), - } - AsteriscKonaPreStatesURLFlag = &cli.StringFlag{ - Name: "asterisc-kona-prestates-url", - Usage: "Base URL to absolute prestates to use when generating trace data. " + - "Prestates in this directory should be name as .json (asterisc-kona trace type only)", - EnvVars: prefixEnvVars("ASTERISC_KONA_PRESTATES_URL"), - } AsteriscSnapshotFreqFlag = &cli.UintFlag{ Name: "asterisc-snapshot-freq", Usage: "Frequency of asterisc snapshots to generate in VM steps (asterisc trace type only)", @@ -262,7 +254,6 @@ var optionalFlags = []cli.Flag{ CannonBinFlag, CannonServerFlag, CannonPreStateFlag, - CannonPreStatesURLFlag, CannonL2Flag, CannonSnapshotFreqFlag, CannonInfoFreqFlag, @@ -274,8 +265,6 @@ var optionalFlags = []cli.Flag{ AsteriscKonaServerFlag, AsteriscPreStateFlag, AsteriscKonaPreStateFlag, - AsteriscPreStatesURLFlag, - AsteriscKonaPreStatesURLFlag, AsteriscSnapshotFreqFlag, AsteriscInfoFreqFlag, GameWindowFlag, @@ -285,6 +274,7 @@ var optionalFlags = []cli.Flag{ func init() { optionalFlags = append(optionalFlags, oplog.CLIFlags(EnvVarPrefix)...) + optionalFlags = append(optionalFlags, PreStatesURLFlag.Flags()...) optionalFlags = append(optionalFlags, txmgr.CLIFlagsWithDefaults(EnvVarPrefix, txmgr.DefaultChallengerFlagValues)...) optionalFlags = append(optionalFlags, opmetrics.CLIFlags(EnvVarPrefix)...) optionalFlags = append(optionalFlags, oppprof.CLIFlags(EnvVarPrefix)...) @@ -321,8 +311,8 @@ func CheckCannonFlags(ctx *cli.Context) error { if !ctx.IsSet(CannonServerFlag.Name) { return fmt.Errorf("flag %s is required", CannonServerFlag.Name) } - if !ctx.IsSet(CannonPreStateFlag.Name) && !ctx.IsSet(CannonPreStatesURLFlag.Name) { - return fmt.Errorf("flag %s or %s is required", CannonPreStatesURLFlag.Name, CannonPreStateFlag.Name) + if !PreStatesURLFlag.IsSet(ctx, types.TraceTypeCannon) && !ctx.IsSet(CannonPreStateFlag.Name) { + return fmt.Errorf("flag %s or %s is required", PreStatesURLFlag.DefaultName(), CannonPreStateFlag.Name) } return nil } @@ -360,8 +350,8 @@ func CheckAsteriscFlags(ctx *cli.Context) error { if !ctx.IsSet(AsteriscServerFlag.Name) { return fmt.Errorf("flag %s is required", AsteriscServerFlag.Name) } - if !ctx.IsSet(AsteriscPreStateFlag.Name) && !ctx.IsSet(AsteriscPreStatesURLFlag.Name) { - return fmt.Errorf("flag %s or %s is required", AsteriscPreStatesURLFlag.Name, AsteriscPreStateFlag.Name) + if !PreStatesURLFlag.IsSet(ctx, types.TraceTypeAsterisc) && !ctx.IsSet(AsteriscPreStateFlag.Name) { + return fmt.Errorf("flag %s or %s is required", PreStatesURLFlag.DefaultName(), AsteriscPreStateFlag.Name) } return nil } @@ -373,8 +363,8 @@ func CheckAsteriscKonaFlags(ctx *cli.Context) error { if !ctx.IsSet(AsteriscKonaServerFlag.Name) { return fmt.Errorf("flag %s is required", AsteriscKonaServerFlag.Name) } - if !ctx.IsSet(AsteriscKonaPreStateFlag.Name) && !ctx.IsSet(AsteriscKonaPreStatesURLFlag.Name) { - return fmt.Errorf("flag %s or %s is required", AsteriscKonaPreStatesURLFlag.Name, AsteriscKonaPreStateFlag.Name) + if !PreStatesURLFlag.IsSet(ctx, types.TraceTypeAsteriscKona) && !ctx.IsSet(AsteriscKonaPreStateFlag.Name) { + return fmt.Errorf("flag %s or %s is required", PreStatesURLFlag.DefaultName(), AsteriscKonaPreStateFlag.Name) } return nil } @@ -513,29 +503,29 @@ func NewConfigFromCLI(ctx *cli.Context, logger log.Logger) (*config.Config, erro claimants = append(claimants, claimant) } } - var cannonPrestatesURL *url.URL - if ctx.IsSet(CannonPreStatesURLFlag.Name) { - parsed, err := url.Parse(ctx.String(CannonPreStatesURLFlag.Name)) + var cannonPreStatesURL *url.URL + if PreStatesURLFlag.IsSet(ctx, types.TraceTypeCannon) { + val := PreStatesURLFlag.String(ctx, types.TraceTypeCannon) + cannonPreStatesURL, err = url.Parse(val) if err != nil { - return nil, fmt.Errorf("invalid cannon pre states url (%v): %w", ctx.String(CannonPreStatesURLFlag.Name), err) + return nil, fmt.Errorf("invalid %v (%v): %w", PreStatesURLFlag.SourceFlagName(ctx, types.TraceTypeCannon), val, err) } - cannonPrestatesURL = parsed } var asteriscPreStatesURL *url.URL - if ctx.IsSet(AsteriscPreStatesURLFlag.Name) { - parsed, err := url.Parse(ctx.String(AsteriscPreStatesURLFlag.Name)) + if PreStatesURLFlag.IsSet(ctx, types.TraceTypeAsterisc) { + val := PreStatesURLFlag.String(ctx, types.TraceTypeAsterisc) + asteriscPreStatesURL, err = url.Parse(val) if err != nil { - return nil, fmt.Errorf("invalid asterisc pre states url (%v): %w", ctx.String(AsteriscPreStatesURLFlag.Name), err) + return nil, fmt.Errorf("invalid %v (%v): %w", PreStatesURLFlag.SourceFlagName(ctx, types.TraceTypeAsterisc), val, err) } - asteriscPreStatesURL = parsed } var asteriscKonaPreStatesURL *url.URL - if ctx.IsSet(AsteriscKonaPreStatesURLFlag.Name) { - parsed, err := url.Parse(ctx.String(AsteriscKonaPreStatesURLFlag.Name)) + if PreStatesURLFlag.IsSet(ctx, types.TraceTypeAsteriscKona) { + val := PreStatesURLFlag.String(ctx, types.TraceTypeAsteriscKona) + asteriscKonaPreStatesURL, err = url.Parse(val) if err != nil { - return nil, fmt.Errorf("invalid asterisc-kona pre states url (%v): %w", ctx.String(AsteriscKonaPreStatesURLFlag.Name), err) + return nil, fmt.Errorf("invalid %v (%v): %w", PreStatesURLFlag.SourceFlagName(ctx, types.TraceTypeAsteriscKona), val, err) } - asteriscKonaPreStatesURL = parsed } l2Rpc, err := getL2Rpc(ctx, logger) if err != nil { @@ -581,7 +571,7 @@ func NewConfigFromCLI(ctx *cli.Context, logger log.Logger) (*config.Config, erro BinarySnapshots: true, }, CannonAbsolutePreState: ctx.String(CannonPreStateFlag.Name), - CannonAbsolutePreStateBaseURL: cannonPrestatesURL, + CannonAbsolutePreStateBaseURL: cannonPreStatesURL, Datadir: ctx.String(DatadirFlag.Name), Asterisc: vm.Config{ VmType: types.TraceTypeAsterisc, diff --git a/op-challenger/flags/vm_flag.go b/op-challenger/flags/vm_flag.go new file mode 100644 index 000000000000..8464f7e5fdd4 --- /dev/null +++ b/op-challenger/flags/vm_flag.go @@ -0,0 +1,70 @@ +package flags + +import ( + "fmt" + + "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" + opservice "github.com/ethereum-optimism/optimism/op-service" + "github.com/urfave/cli/v2" +) + +type FlagCreator func(name string, envVars []string, traceTypeInfo string) cli.Flag + +// VMFlag defines a set of flags to set a VM specific option. Provides a flag to set the default plus flags to +// override the default on a per VM basis. +type VMFlag struct { + vms []types.TraceType + name string + envVarPrefix string + flagCreator FlagCreator +} + +func NewVMFlag(name string, envVarPrefix string, vms []types.TraceType, flagCreator FlagCreator) *VMFlag { + return &VMFlag{ + name: name, + envVarPrefix: envVarPrefix, + flagCreator: flagCreator, + vms: vms, + } +} + +func (f *VMFlag) Flags() []cli.Flag { + flags := make([]cli.Flag, 0, len(f.vms)) + // Default + defaultEnvVar := opservice.FlagNameToEnvVarName(f.name, f.envVarPrefix) + flags = append(flags, f.flagCreator(f.name, []string{defaultEnvVar}, "")) + for _, vm := range f.vms { + name := f.flagName(vm) + envVar := opservice.FlagNameToEnvVarName(name, f.envVarPrefix) + flags = append(flags, f.flagCreator(name, []string{envVar}, fmt.Sprintf("(%v trace type only)", vm))) + } + return flags +} + +func (f *VMFlag) DefaultName() string { + return f.name +} + +func (f *VMFlag) IsSet(ctx *cli.Context, vm types.TraceType) bool { + return ctx.IsSet(f.flagName(vm)) || ctx.IsSet(f.name) +} + +func (f *VMFlag) String(ctx *cli.Context, vm types.TraceType) string { + val := ctx.String(f.flagName(vm)) + if val == "" { + val = ctx.String(f.name) + } + return val +} + +func (f *VMFlag) SourceFlagName(ctx *cli.Context, vm types.TraceType) string { + vmFlag := f.flagName(vm) + if ctx.IsSet(vmFlag) { + return vmFlag + } + return f.name +} + +func (f *VMFlag) flagName(vm types.TraceType) string { + return fmt.Sprintf("%v-%v", vm, f.name) +} diff --git a/op-challenger/game/fault/trace/prestates/source.go b/op-challenger/game/fault/trace/prestates/source.go index a4c9839ad1e5..cc6cdcf2bfe9 100644 --- a/op-challenger/game/fault/trace/prestates/source.go +++ b/op-challenger/game/fault/trace/prestates/source.go @@ -7,9 +7,9 @@ import ( ) func NewPrestateSource(baseURL *url.URL, path string, localDir string, stateConverter vm.StateConverter) PrestateSource { - if baseURL != nil { - return NewMultiPrestateProvider(baseURL, localDir, stateConverter) - } else { + if path != "" { return NewSinglePrestateSource(path) + } else { + return NewMultiPrestateProvider(baseURL, localDir, stateConverter) } } diff --git a/op-challenger/game/fault/trace/prestates/source_test.go b/op-challenger/game/fault/trace/prestates/source_test.go new file mode 100644 index 000000000000..75ebaa76decd --- /dev/null +++ b/op-challenger/game/fault/trace/prestates/source_test.go @@ -0,0 +1,15 @@ +package prestates + +import ( + "net/url" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPreferSinglePrestate(t *testing.T) { + uri, err := url.Parse("http://localhost") + require.NoError(t, err) + source := NewPrestateSource(uri, "/tmp/path.json", t.TempDir(), nil) + require.IsType(t, &SinglePrestateSource{}, source) +}