Commit 74728d9b authored by asnared's avatar asnared Committed by Andreas Bigger

Challenger Trace Type Flags

parent f4411c56
......@@ -7,6 +7,8 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
"github.com/ethereum-optimism/optimism/op-challenger/fault/cannon"
"github.com/ethereum-optimism/optimism/op-challenger/flags"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum-optimism/optimism/op-service/txmgr/metrics"
"github.com/ethereum/go-ethereum/ethclient"
......@@ -36,7 +38,13 @@ func Main(ctx context.Context, logger log.Logger, cfg *config.Config) error {
if err != nil {
return fmt.Errorf("failed to create the responder: %w", err)
}
trace := fault.NewAlphabetProvider(cfg.AlphabetTrace, uint64(cfg.GameDepth))
var trace fault.TraceProvider
if cfg.TraceType == flags.CannonTraceType {
trace = cannon.NewCannonTraceProvider(cfg.CannonDatadir)
} else if cfg.TraceType == flags.AlphabetTraceType {
trace = fault.NewAlphabetProvider(cfg.AlphabetTrace, uint64(cfg.GameDepth))
}
agent := fault.NewAgent(loader, cfg.GameDepth, trace, responder, cfg.AgreeWithProposedOutput, gameLogger)
......
......@@ -16,6 +16,7 @@ FAULT_GAME_ADDRESS="0x8daf17a20c9dba35f005b6324f493785d239719d"
./bin/op-challenger \
--l1-eth-rpc http://localhost:8545 \
--trace-type="alphabet" \
--alphabet "abcdefgh" \
--game-address $FAULT_GAME_ADDRESS \
--private-key $CHARLIE_KEY \
......
......@@ -6,6 +6,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/flags"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
......@@ -15,6 +16,7 @@ import (
var (
l1EthRpc = "http://example.com:8545"
gameAddressValue = "0xaa00000000000000000000000000000000000000"
cannonDatadir = "./test_data"
alphabetTrace = "abcdefghijz"
agreeWithProposedOutput = "true"
gameDepth = "4"
......@@ -37,12 +39,12 @@ func TestLogLevel(t *testing.T) {
func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs())
defaultCfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), alphabetTrace, true, 4)
defaultCfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), flags.AlphabetTraceType, alphabetTrace, cannonDatadir, true, 4)
require.Equal(t, defaultCfg, cfg)
}
func TestDefaultConfigIsValid(t *testing.T) {
cfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), alphabetTrace, true, 4)
cfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), flags.AlphabetTraceType, alphabetTrace, cannonDatadir, true, 4)
require.NoError(t, cfg.Check())
}
......@@ -59,15 +61,14 @@ func TestL1ETHRPCAddress(t *testing.T) {
})
}
func TestAlphabetTrace(t *testing.T) {
func TestTraceType(t *testing.T) {
t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag alphabet is required", addRequiredArgsExcept("--alphabet"))
verifyArgsInvalid(t, "flag trace-type is required", addRequiredArgsExcept("--trace-type"))
})
t.Run("Valid", func(t *testing.T) {
value := "abcde"
cfg := configForArgs(t, addRequiredArgsExcept("--alphabet", "--alphabet="+value))
require.Equal(t, value, cfg.AlphabetTrace)
cfg := configForArgs(t, addRequiredArgsExcept("--trace-type", "--trace-type="+flags.AlphabetTraceType))
require.Equal(t, flags.AlphabetTraceType, cfg.TraceType)
})
}
......@@ -164,7 +165,9 @@ func requiredArgs() map[string]string {
"--agree-with-proposed-output": agreeWithProposedOutput,
"--l1-eth-rpc": l1EthRpc,
"--game-address": gameAddressValue,
"--trace-type": flags.AlphabetTraceType,
"--alphabet": alphabetTrace,
"--cannon-datadir": cannonDatadir,
}
}
......
......@@ -2,6 +2,7 @@ package config
import (
"errors"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
......@@ -12,9 +13,11 @@ import (
)
var (
ErrMissingTraceType = errors.New("missing trace type")
ErrMissingCannonDatadir = errors.New("missing cannon datadir")
ErrMissingAlphabetTrace = errors.New("missing alphabet trace")
ErrMissingL1EthRPC = errors.New("missing l1 eth rpc url")
ErrMissingGameAddress = errors.New("missing game address")
ErrMissingAlphabetTrace = errors.New("missing alphabet trace")
)
// Config is a well typed config that is parsed from the CLI params.
......@@ -23,27 +26,37 @@ var (
type Config struct {
L1EthRpc string // L1 RPC Url
GameAddress common.Address // Address of the fault game
AlphabetTrace string // String for the AlphabetTraceProvider
AgreeWithProposedOutput bool // Temporary config if we agree or disagree with the posted output
GameDepth int // Depth of the game tree
TraceType string // Type of trace
AlphabetTrace string // String for the AlphabetTraceProvider
CannonDatadir string // Cannon Data Directory for the CannonTraceProvider
TxMgrConfig txmgr.CLIConfig
}
func NewConfig(
l1EthRpc string,
GameAddress common.Address,
AlphabetTrace string,
AgreeWithProposedOutput bool,
GameDepth int,
gameAddress common.Address,
traceType string,
alphabetTrace string,
cannonDatadir string,
agreeWithProposedOutput bool,
gameDepth int,
) Config {
return Config{
L1EthRpc: l1EthRpc,
GameAddress: GameAddress,
AlphabetTrace: AlphabetTrace,
TxMgrConfig: txmgr.NewCLIConfig(l1EthRpc),
AgreeWithProposedOutput: AgreeWithProposedOutput,
GameDepth: GameDepth,
L1EthRpc: l1EthRpc,
GameAddress: gameAddress,
AgreeWithProposedOutput: agreeWithProposedOutput,
GameDepth: gameDepth,
TraceType: traceType,
AlphabetTrace: alphabetTrace,
CannonDatadir: cannonDatadir,
TxMgrConfig: txmgr.NewCLIConfig(l1EthRpc),
}
}
......@@ -54,7 +67,13 @@ func (c Config) Check() error {
if c.GameAddress == (common.Address{}) {
return ErrMissingGameAddress
}
if c.AlphabetTrace == "" {
if c.TraceType == "" {
return ErrMissingTraceType
}
if c.TraceType == flags.CannonTraceType && c.CannonDatadir == "" {
return ErrMissingCannonDatadir
}
if c.TraceType == flags.AlphabetTraceType && c.AlphabetTrace == "" {
return ErrMissingAlphabetTrace
}
if err := c.TxMgrConfig.Check(); err != nil {
......@@ -75,11 +94,16 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
txMgrConfig := txmgr.ReadCLIConfig(ctx)
traceTypeFlag := strings.TrimLeft(ctx.String(flags.TraceTypeFlag.Name), "[")
traceTypeFlag = strings.TrimRight(traceTypeFlag, "]")
return &Config{
// Required Flags
L1EthRpc: ctx.String(flags.L1EthRpcFlag.Name),
TraceType: traceTypeFlag,
GameAddress: dgfAddress,
AlphabetTrace: ctx.String(flags.AlphabetFlag.Name),
CannonDatadir: ctx.String(flags.CannonDatadirFlag.Name),
AgreeWithProposedOutput: ctx.Bool(flags.AgreeWithProposedOutputFlag.Name),
GameDepth: ctx.Int(flags.GameDepthFlag.Name),
TxMgrConfig: txMgrConfig,
......
......@@ -3,6 +3,7 @@ package config
import (
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/flags"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
......@@ -12,47 +13,58 @@ var (
validL1EthRpc = "http://localhost:8545"
validGameAddress = common.HexToAddress("0x7bdd3b028C4796eF0EAf07d11394d0d9d8c24139")
validAlphabetTrace = "abcdefgh"
validCannonDatadir = "/tmp/cannon"
agreeWithProposedOutput = true
gameDepth = 4
)
func validConfig() Config {
cfg := NewConfig(validL1EthRpc, validGameAddress, validAlphabetTrace, agreeWithProposedOutput, gameDepth)
func validConfig(traceType string) Config {
cfg := NewConfig(validL1EthRpc, validGameAddress, traceType, validAlphabetTrace, validCannonDatadir, agreeWithProposedOutput, gameDepth)
return cfg
}
// TestValidConfigIsValid checks that the config provided by validConfig is actually valid
func TestValidConfigIsValid(t *testing.T) {
err := validConfig().Check()
err := validConfig(flags.CannonTraceType).Check()
require.NoError(t, err)
}
func TestTxMgrConfig(t *testing.T) {
t.Run("Invalid", func(t *testing.T) {
config := validConfig()
config := validConfig(flags.CannonTraceType)
config.TxMgrConfig = txmgr.CLIConfig{}
err := config.Check()
require.Equal(t, err.Error(), "must provide a L1 RPC url")
require.Equal(t, config.Check().Error(), "must provide a L1 RPC url")
})
}
func TestL1EthRpcRequired(t *testing.T) {
config := validConfig()
config := validConfig(flags.CannonTraceType)
config.L1EthRpc = ""
err := config.Check()
require.ErrorIs(t, err, ErrMissingL1EthRPC)
require.ErrorIs(t, config.Check(), ErrMissingL1EthRPC)
config.L1EthRpc = validL1EthRpc
require.NoError(t, config.Check())
}
func TestGameAddressRequired(t *testing.T) {
config := validConfig()
config := validConfig(flags.CannonTraceType)
config.GameAddress = common.Address{}
err := config.Check()
require.ErrorIs(t, err, ErrMissingGameAddress)
require.ErrorIs(t, config.Check(), ErrMissingGameAddress)
config.GameAddress = validGameAddress
require.NoError(t, config.Check())
}
func TestAlphabetTraceRequired(t *testing.T) {
config := validConfig()
config := validConfig(flags.AlphabetTraceType)
config.AlphabetTrace = ""
err := config.Check()
require.ErrorIs(t, err, ErrMissingAlphabetTrace)
require.ErrorIs(t, config.Check(), ErrMissingAlphabetTrace)
config.AlphabetTrace = validAlphabetTrace
require.NoError(t, config.Check())
}
func TestCannonTraceRequired(t *testing.T) {
config := validConfig(flags.CannonTraceType)
config.CannonDatadir = ""
require.ErrorIs(t, config.Check(), ErrMissingCannonDatadir)
config.CannonDatadir = validCannonDatadir
require.NoError(t, config.Check())
}
......@@ -10,12 +10,21 @@ import (
txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
)
const envVarPrefix = "OP_CHALLENGER"
const (
envVarPrefix = "OP_CHALLENGER"
CannonTraceType = "cannon"
AlphabetTraceType = "alphabet"
)
func prefixEnvVars(name string) []string {
return opservice.PrefixEnvVar(envVarPrefix, name)
}
var (
validTraceTypes = []string{CannonTraceType, AlphabetTraceType}
traceTypes = cli.NewStringSlice(validTraceTypes...)
)
var (
// Required Flags
L1EthRpcFlag = &cli.StringFlag{
......@@ -28,10 +37,11 @@ var (
Usage: "Address of the Fault Game contract.",
EnvVars: prefixEnvVars("GAME_ADDRESS"),
}
AlphabetFlag = &cli.StringFlag{
Name: "alphabet",
Usage: "Alphabet Trace (temporary)",
EnvVars: prefixEnvVars("ALPHABET"),
TraceTypeFlag = &cli.StringSliceFlag{
Value: traceTypes,
Name: "trace-type",
Usage: "The trace type.",
EnvVars: prefixEnvVars("TRACE_TYPE"),
}
AgreeWithProposedOutputFlag = &cli.BoolFlag{
Name: "agree-with-proposed-output",
......@@ -44,19 +54,32 @@ var (
EnvVars: prefixEnvVars("GAME_DEPTH"),
}
// Optional Flags
AlphabetFlag = &cli.StringFlag{
Name: "alphabet",
Usage: "Alphabet Trace (temporary)",
EnvVars: prefixEnvVars("ALPHABET"),
}
CannonDatadirFlag = &cli.StringFlag{
Name: "cannon-datadir",
Usage: "Cannon Data Directory",
EnvVars: prefixEnvVars("CANNON_DATADIR"),
}
)
// requiredFlags are checked by [CheckRequired]
var requiredFlags = []cli.Flag{
L1EthRpcFlag,
DGFAddressFlag,
AlphabetFlag,
TraceTypeFlag,
AgreeWithProposedOutputFlag,
GameDepthFlag,
}
// optionalFlags is a list of unchecked cli flags
var optionalFlags = []cli.Flag{}
var optionalFlags = []cli.Flag{
AlphabetFlag,
CannonDatadirFlag,
}
func init() {
optionalFlags = append(optionalFlags, oplog.CLIFlags(envVarPrefix)...)
......@@ -74,5 +97,17 @@ func CheckRequired(ctx *cli.Context) error {
return fmt.Errorf("flag %s is required", f.Names()[0])
}
}
switch ctx.String(TraceTypeFlag.Name) {
case "[" + CannonTraceType + "]":
if !ctx.IsSet(CannonDatadirFlag.Name) {
return fmt.Errorf("flag %s is required", "cannon-datadir")
}
case "[" + AlphabetTraceType + "]":
if !ctx.IsSet(AlphabetFlag.Name) {
return fmt.Errorf("flag %s is required", "alphabet")
}
default:
return fmt.Errorf("invalid trace type. must be one of %v", validTraceTypes)
}
return nil
}
......@@ -16,6 +16,7 @@ FAULT_GAME_ADDRESS="0x8daf17a20c9dba35f005b6324f493785d239719d"
./bin/op-challenger \
--l1-eth-rpc http://localhost:8545 \
--trace-type="alphabet" \
--alphabet "abcdexyz" \
--game-address $FAULT_GAME_ADDRESS \
--private-key $MALLORY_KEY \
......
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