Commit 292eb443 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Add beacon api endpoint to op-challenger (#9407)

* op-challenger: Add beacon api endpoint to op-challenger

Set as required as ecotone is expected to be active before fault proofs launches.

* devnet: Set L1_BEACON for challenger

* op-challenger: Move flags into required section

* cannon: Update example go.mod
parent ea17584c
......@@ -8,7 +8,7 @@ require github.com/ethereum-optimism/optimism v0.0.0
require (
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/sys v0.17.0 // indirect
)
replace github.com/ethereum-optimism/optimism v0.0.0 => ../../..
......@@ -6,7 +6,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
......@@ -19,6 +19,7 @@ import (
var (
l1EthRpc = "http://example.com:8545"
l1Beacon = "http://example.com:9000"
gameFactoryAddressValue = "0xbb00000000000000000000000000000000000000"
cannonNetwork = "op-mainnet"
otherCannonNetwork = "op-goerli"
......@@ -47,14 +48,14 @@ func TestLogLevel(t *testing.T) {
func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs(config.TraceTypeAlphabet))
defaultCfg := config.NewConfig(common.HexToAddress(gameFactoryAddressValue), l1EthRpc, datadir, config.TraceTypeAlphabet)
defaultCfg := config.NewConfig(common.HexToAddress(gameFactoryAddressValue), l1EthRpc, l1Beacon, datadir, config.TraceTypeAlphabet)
// Add in the extra CLI options required when using alphabet trace type
defaultCfg.RollupRpc = rollupRpc
require.Equal(t, defaultCfg, cfg)
}
func TestDefaultConfigIsValid(t *testing.T) {
cfg := config.NewConfig(common.HexToAddress(gameFactoryAddressValue), l1EthRpc, datadir, config.TraceTypeAlphabet)
cfg := config.NewConfig(common.HexToAddress(gameFactoryAddressValue), l1EthRpc, l1Beacon, datadir, config.TraceTypeAlphabet)
// Add in options that are required based on the specific trace type
// To avoid needing to specify unused options, these aren't included in the params for NewConfig
cfg.RollupRpc = rollupRpc
......@@ -74,6 +75,18 @@ func TestL1ETHRPCAddress(t *testing.T) {
})
}
func TestL1Beacon(t *testing.T) {
t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag l1-beacon is required", addRequiredArgsExcept(config.TraceTypeAlphabet, "--l1-beacon"))
})
t.Run("Valid", func(t *testing.T) {
url := "http://example.com:8888"
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--l1-beacon", "--l1-beacon="+url))
require.Equal(t, url, cfg.L1Beacon)
})
}
func TestTraceType(t *testing.T) {
t.Run("Default", func(t *testing.T) {
expectedDefault := config.TraceTypeCannon
......@@ -472,6 +485,7 @@ func addRequiredArgsExcept(traceType config.TraceType, name string, optionalArgs
func requiredArgs(traceType config.TraceType) map[string]string {
args := map[string]string{
"--l1-eth-rpc": l1EthRpc,
"--l1-beacon": l1Beacon,
"--game-factory-address": gameFactoryAddressValue,
"--trace-type": traceType.String(),
"--datadir": datadir,
......
......@@ -24,6 +24,7 @@ var (
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")
......@@ -100,6 +101,7 @@ const (
// It is used to initialize the challenger.
type Config struct {
L1EthRpc string // L1 RPC Url
L1Beacon string // L1 Beacon API Url
GameFactoryAddress common.Address // Address of the dispute game factory
GameAllowlist []common.Address // Allowlist of fault game addresses
GameWindow time.Duration // Maximum time duration to look for games to progress
......@@ -133,11 +135,13 @@ type Config struct {
func NewConfig(
gameFactoryAddress common.Address,
l1EthRpc string,
l1BeaconApi string,
datadir string,
supportedTraceTypes ...TraceType,
) Config {
return Config{
L1EthRpc: l1EthRpc,
L1Beacon: l1BeaconApi,
GameFactoryAddress: gameFactoryAddress,
MaxConcurrency: uint(runtime.NumCPU()),
PollInterval: DefaultPollInterval,
......@@ -166,6 +170,9 @@ func (c Config) Check() error {
if c.L1EthRpc == "" {
return ErrMissingL1EthRPC
}
if c.L1Beacon == "" {
return ErrMissingL1Beacon
}
if c.RollupRpc == "" {
return ErrMissingRollupRpc
}
......
......@@ -12,6 +12,7 @@ import (
var (
validL1EthRpc = "http://localhost:8545"
validL1BeaconUrl = "http://localhost:9000"
validGameFactoryAddress = common.Address{0x23}
validCannonBin = "./bin/cannon"
validCannonOpProgramBin = "./bin/op-program"
......@@ -23,7 +24,7 @@ var (
)
func validConfig(traceType TraceType) Config {
cfg := NewConfig(validGameFactoryAddress, validL1EthRpc, validDatadir, traceType)
cfg := NewConfig(validGameFactoryAddress, validL1EthRpc, validL1BeaconUrl, validDatadir, traceType)
if traceType == TraceTypeCannon {
cfg.CannonBin = validCannonBin
cfg.CannonServer = validCannonOpProgramBin
......@@ -60,6 +61,12 @@ func TestL1EthRpcRequired(t *testing.T) {
require.ErrorIs(t, config.Check(), ErrMissingL1EthRPC)
}
func TestL1BeaconRequired(t *testing.T) {
config := validConfig(TraceTypeCannon)
config.L1Beacon = ""
require.ErrorIs(t, config.Check(), ErrMissingL1Beacon)
}
func TestGameFactoryAddressRequired(t *testing.T) {
config := validConfig(TraceTypeCannon)
config.GameFactoryAddress = common.Address{}
......
......@@ -32,6 +32,16 @@ var (
Usage: "HTTP provider URL for L1.",
EnvVars: prefixEnvVars("L1_ETH_RPC"),
}
L1BeaconFlag = &cli.StringFlag{
Name: "l1-beacon",
Usage: "Address of L1 Beacon API endpoint to use",
EnvVars: prefixEnvVars("L1_BEACON"),
}
RollupRpcFlag = &cli.StringFlag{
Name: "rollup-rpc",
Usage: "HTTP provider URL for the rollup node",
EnvVars: prefixEnvVars("ROLLUP_RPC"),
}
FactoryAddressFlag = &cli.StringFlag{
Name: "game-factory-address",
Usage: "Address of the fault game factory contract.",
......@@ -73,11 +83,6 @@ var (
EnvVars: prefixEnvVars("HTTP_POLL_INTERVAL"),
Value: config.DefaultPollInterval,
}
RollupRpcFlag = &cli.StringFlag{
Name: "rollup-rpc",
Usage: "HTTP provider URL for the rollup node",
EnvVars: prefixEnvVars("ROLLUP_RPC"),
}
CannonNetworkFlag = &cli.StringFlag{
Name: "cannon-network",
Usage: fmt.Sprintf(
......@@ -142,6 +147,8 @@ var requiredFlags = []cli.Flag{
L1EthRpcFlag,
FactoryAddressFlag,
DatadirFlag,
RollupRpcFlag,
L1BeaconFlag,
}
// optionalFlags is a list of unchecked cli flags
......@@ -150,7 +157,6 @@ var optionalFlags = []cli.Flag{
MaxConcurrencyFlag,
MaxPendingTransactionsFlag,
HTTPPollInterval,
RollupRpcFlag,
GameAllowlistFlag,
CannonNetworkFlag,
CannonRollupConfigFlag,
......@@ -214,13 +220,7 @@ func CheckRequired(ctx *cli.Context, traceTypes []config.TraceType) error {
if err := CheckCannonFlags(ctx); err != nil {
return err
}
if !ctx.IsSet(RollupRpcFlag.Name) {
return fmt.Errorf("flag %s is required", RollupRpcFlag.Name)
}
case config.TraceTypeAlphabet:
if !ctx.IsSet(RollupRpcFlag.Name) {
return fmt.Errorf("flag %s is required", RollupRpcFlag.Name)
}
default:
return fmt.Errorf("invalid trace type. must be one of %v", config.TraceTypes)
}
......@@ -277,6 +277,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
return &config.Config{
// Required Flags
L1EthRpc: ctx.String(L1EthRpcFlag.Name),
L1Beacon: ctx.String(L1BeaconFlag.Name),
TraceTypes: traceTypes,
GameFactoryAddress: gameFactoryAddress,
GameAllowlist: allowedGames,
......
......@@ -33,6 +33,7 @@ type Executor struct {
logger log.Logger
metrics CannonMetricer
l1 string
l1Beacon string
l2 string
inputs LocalGameInputs
cannon string
......@@ -52,6 +53,7 @@ func NewExecutor(logger log.Logger, m CannonMetricer, cfg *config.Config, inputs
logger: logger,
metrics: m,
l1: cfg.L1EthRpc,
l1Beacon: cfg.L1Beacon,
l2: cfg.CannonL2,
inputs: inputs,
cannon: cfg.CannonBin,
......@@ -104,6 +106,7 @@ func (e *Executor) generateProof(ctx context.Context, dir string, begin uint64,
"--",
e.server, "--server",
"--l1", e.l1,
"--l1.beacon", e.l1Beacon,
"--l2", e.l2,
"--datadir", dataDir,
"--l1.head", e.inputs.L1Head.Hex(),
......
......@@ -24,7 +24,7 @@ func TestGenerateProof(t *testing.T) {
input := "starting.json"
tempDir := t.TempDir()
dir := filepath.Join(tempDir, "gameDir")
cfg := config.NewConfig(common.Address{0xbb}, "http://localhost:8888", tempDir, config.TraceTypeCannon)
cfg := config.NewConfig(common.Address{0xbb}, "http://localhost:8888", "http://localhost:9000", tempDir, config.TraceTypeCannon)
cfg.CannonAbsolutePreState = "pre.json"
cfg.CannonBin = "./bin/cannon"
cfg.CannonServer = "./bin/op-program"
......@@ -91,6 +91,7 @@ func TestGenerateProof(t *testing.T) {
// Then everything else pairs off correctly again
require.Equal(t, "--server", args[cfg.CannonServer])
require.Equal(t, cfg.L1EthRpc, args["--l1"])
require.Equal(t, cfg.L1Beacon, args["--l1.beacon"])
require.Equal(t, cfg.CannonL2, args["--l2"])
require.Equal(t, filepath.Join(dir, preimagesDir), args["--datadir"])
require.Equal(t, filepath.Join(dir, proofsDir, "%d.json.gz"), args["--proof-fmt"])
......
......@@ -27,6 +27,11 @@ import (
"github.com/ethereum-optimism/optimism/op-service/testlog"
)
type EndpointProvider interface {
NodeEndpoint(name string) string
L1BeaconEndpoint() string
}
type Helper struct {
log log.Logger
t *testing.T
......@@ -109,10 +114,10 @@ func WithAlphabet(rollupEndpoint string) Option {
}
}
func NewChallenger(t *testing.T, ctx context.Context, l1Endpoint string, name string, options ...Option) *Helper {
func NewChallenger(t *testing.T, ctx context.Context, sys EndpointProvider, name string, options ...Option) *Helper {
log := testlog.Logger(t, log.LevelDebug).New("role", name)
log.Info("Creating challenger", "l1", l1Endpoint)
cfg := NewChallengerConfig(t, l1Endpoint, options...)
log.Info("Creating challenger")
cfg := NewChallengerConfig(t, sys, options...)
chl, err := challenger.Main(ctx, log, cfg)
require.NoError(t, err, "must init challenger")
require.NoError(t, chl.Start(ctx), "must start challenger")
......@@ -126,9 +131,11 @@ func NewChallenger(t *testing.T, ctx context.Context, l1Endpoint string, name st
}
}
func NewChallengerConfig(t *testing.T, l1Endpoint string, options ...Option) *config.Config {
func NewChallengerConfig(t *testing.T, sys EndpointProvider, options ...Option) *config.Config {
// Use the NewConfig method to ensure we pick up any defaults that are set.
cfg := config.NewConfig(common.Address{}, l1Endpoint, t.TempDir())
l1Endpoint := sys.NodeEndpoint("l1")
l1Beacon := sys.L1BeaconEndpoint()
cfg := config.NewConfig(common.Address{}, l1Endpoint, l1Beacon, t.TempDir())
cfg.TxMgrConfig.NumConfirmations = 1
cfg.TxMgrConfig.ReceiptQueryInterval = 1 * time.Second
if cfg.MaxConcurrency > 4 {
......
......@@ -13,14 +13,14 @@ type AlphabetGameHelper struct {
FaultGameHelper
}
func (g *AlphabetGameHelper) StartChallenger(ctx context.Context, l1Endpoint string, name string, options ...challenger.Option) *challenger.Helper {
func (g *AlphabetGameHelper) StartChallenger(ctx context.Context, sys challenger.EndpointProvider, name string, options ...challenger.Option) *challenger.Helper {
opts := []challenger.Option{
challenger.WithFactoryAddress(g.factoryAddr),
challenger.WithGameAddress(g.addr),
challenger.WithAlphabet(g.system.RollupEndpoint("sequencer")),
}
opts = append(opts, options...)
c := challenger.NewChallenger(g.t, ctx, l1Endpoint, name, opts...)
c := challenger.NewChallenger(g.t, ctx, sys, name, opts...)
g.t.Cleanup(func() {
_ = c.Close()
})
......
......@@ -58,6 +58,7 @@ func (s Status) String() string {
}
type DisputeSystem interface {
L1BeaconEndpoint() string
NodeEndpoint(name string) string
NodeClient(name string) *ethclient.Client
RollupEndpoint(name string) string
......@@ -242,7 +243,7 @@ func (h *FactoryHelper) StartChallenger(ctx context.Context, name string, option
challenger.WithFactoryAddress(h.factoryAddr),
}
opts = append(opts, options...)
c := challenger.NewChallenger(h.t, ctx, h.system.NodeEndpoint("l1"), name, opts...)
c := challenger.NewChallenger(h.t, ctx, h.system, name, opts...)
h.t.Cleanup(func() {
_ = c.Close()
})
......
......@@ -28,7 +28,7 @@ func (g *OutputAlphabetGameHelper) StartChallenger(
challenger.WithGameAddress(g.addr),
}
opts = append(opts, options...)
c := challenger.NewChallenger(g.t, ctx, g.system.NodeEndpoint("l1"), name, opts...)
c := challenger.NewChallenger(g.t, ctx, g.system, name, opts...)
g.t.Cleanup(func() {
_ = c.Close()
})
......
......@@ -40,7 +40,7 @@ func (g *OutputCannonGameHelper) StartChallenger(
challenger.WithGameAddress(g.addr),
}
opts = append(opts, options...)
c := challenger.NewChallenger(g.t, ctx, g.system.NodeEndpoint("l1"), name, opts...)
c := challenger.NewChallenger(g.t, ctx, g.system, name, opts...)
g.t.Cleanup(func() {
_ = c.Close()
})
......@@ -50,7 +50,7 @@ func (g *OutputCannonGameHelper) StartChallenger(
func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node string, options ...challenger.Option) *OutputHonestHelper {
opts := g.defaultChallengerOptions(l2Node)
opts = append(opts, options...)
cfg := challenger.NewChallengerConfig(g.t, g.system.NodeEndpoint("l1"), opts...)
cfg := challenger.NewChallengerConfig(g.t, g.system, opts...)
logger := testlog.Logger(g.t, log.LevelInfo).New("role", "HonestHelper", "game", g.addr)
l2Client := g.system.NodeClient(l2Node)
......@@ -219,7 +219,7 @@ func (g *OutputCannonGameHelper) createCannonTraceProvider(ctx context.Context,
logger := testlog.Logger(g.t, log.LevelInfo).New("role", "CannonTraceProvider", "game", g.addr)
opt := g.defaultChallengerOptions(l2Node)
opt = append(opt, options...)
cfg := challenger.NewChallengerConfig(g.t, g.system.NodeEndpoint("l1"), opt...)
cfg := challenger.NewChallengerConfig(g.t, g.system, opt...)
caller := batching.NewMultiCaller(g.system.NodeClient("l1").Client(), batching.DefaultBatchSize)
l2Client := g.system.NodeClient(l2Node)
......
......@@ -298,6 +298,10 @@ func (sys *System) AdvanceTime(d time.Duration) {
}
}
func (sys *System) L1BeaconEndpoint() string {
return sys.L1BeaconAPIAddr
}
func (sys *System) NodeEndpoint(name string) string {
return selectEndpoint(sys.EthInstances[name])
}
......
......@@ -79,7 +79,6 @@ var (
Name: "l1.beacon",
Usage: "Address of L1 Beacon API endpoint to use",
EnvVars: prefixEnvVars("L1_BEACON_API"),
Hidden: true,
}
L1TrustRPC = &cli.BoolFlag{
Name: "l1.trustrpc",
......
......@@ -178,6 +178,8 @@ services:
image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:devnet
environment:
OP_CHALLENGER_L1_ETH_RPC: http://l1:8545
# Note: this will need to be updated to point to a L1 consensus node when there is one in the devnet
OP_CHALLENGER_L1_BEACON: "unset"
OP_CHALLENGER_ROLLUP_RPC: http://op-node:8545
OP_CHALLENGER_TRACE_TYPE: cannon
OP_CHALLENGER_GAME_FACTORY_ADDRESS: ${DGF_ADDRESS}
......
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