Skip to content

Commit

Permalink
op-challenger: Support running multiple prestates the same game type …
Browse files Browse the repository at this point in the history
…in run-trace (ethereum-optimism#12443)
  • Loading branch information
ajsutton authored Oct 14, 2024
1 parent 1ac85ca commit d41e588
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 131 deletions.
97 changes: 61 additions & 36 deletions op-challenger/cmd/run_trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ import (
"context"
"errors"
"fmt"
"net/url"
"slices"
"strings"

"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/flags"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/runner"
opservice "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/cliapp"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
)

func RunTrace(ctx *cli.Context, _ context.CancelCauseFunc) (cliapp.Lifecycle, error) {
var (
ErrUnknownTraceType = errors.New("unknown trace type")
ErrInvalidPrestateHash = errors.New("invalid prestate hash")
)

func RunTrace(ctx *cli.Context, _ context.CancelCauseFunc) (cliapp.Lifecycle, error) {
logger, err := setupLogging(ctx)
if err != nil {
return nil, err
Expand All @@ -31,36 +35,21 @@ func RunTrace(ctx *cli.Context, _ context.CancelCauseFunc) (cliapp.Lifecycle, er
if err := cfg.Check(); err != nil {
return nil, err
}
if err := checkMTCannonFlags(ctx, cfg); err != nil {
runConfigs, err := parseRunArgs(ctx.StringSlice(RunTraceRunFlag.Name))
if err != nil {
return nil, err
}

var mtPrestate common.Hash
var mtPrestateURL *url.URL
if ctx.IsSet(addMTCannonPrestateFlag.Name) {
mtPrestate = common.HexToHash(ctx.String(addMTCannonPrestateFlag.Name))
mtPrestateURL, err = url.Parse(ctx.String(addMTCannonPrestateURLFlag.Name))
if err != nil {
return nil, fmt.Errorf("invalid mt-cannon prestate url (%v): %w", ctx.String(addMTCannonPrestateFlag.Name), err)
if len(runConfigs) == 0 {
// Default to running on-chain version of each enabled trace type
for _, traceType := range cfg.TraceTypes {
runConfigs = append(runConfigs, runner.RunConfig{TraceType: traceType})
}
}
return runner.NewRunner(logger, cfg, mtPrestate, mtPrestateURL), nil
}

func checkMTCannonFlags(ctx *cli.Context, cfg *config.Config) error {
if ctx.IsSet(addMTCannonPrestateFlag.Name) || ctx.IsSet(addMTCannonPrestateURLFlag.Name) {
if ctx.IsSet(addMTCannonPrestateFlag.Name) != ctx.IsSet(addMTCannonPrestateURLFlag.Name) {
return fmt.Errorf("both flag %v and %v must be set when running MT-Cannon traces", addMTCannonPrestateURLFlag.Name, addMTCannonPrestateFlag.Name)
}
if cfg.Cannon == (vm.Config{}) {
return errors.New("required Cannon vm configuration for mt-cannon traces is missing")
}
}
return nil
return runner.NewRunner(logger, cfg, runConfigs), nil
}

func runTraceFlags() []cli.Flag {
return append(flags.Flags, addMTCannonPrestateFlag, addMTCannonPrestateURLFlag)
return append(flags.Flags, RunTraceRunFlag)
}

var RunTraceCommand = &cli.Command{
Expand All @@ -72,14 +61,50 @@ var RunTraceCommand = &cli.Command{
}

var (
addMTCannonPrestateFlag = &cli.StringFlag{
Name: "add-mt-cannon-prestate",
Usage: "Use this prestate to run MT-Cannon compatibility tests",
EnvVars: opservice.PrefixEnvVar(flags.EnvVarPrefix, "ADD_MT_CANNON_PRESTATE"),
}
addMTCannonPrestateURLFlag = &cli.StringFlag{
Name: "add-mt-cannon-prestate-url",
Usage: "Use this prestate URL to run MT-Cannon compatibility tests",
EnvVars: opservice.PrefixEnvVar(flags.EnvVarPrefix, "ADD_MT_CANNON_PRESTATE_URL"),
RunTraceRunFlag = &cli.StringSliceFlag{
Name: "run",
Usage: "Specify a trace to run. Format is traceType/name/prestateHash where " +
"traceType is the trace type to use with the prestate (e.g cannon or asterisc-kona), " +
"name is an arbitrary name for the prestate to use when reporting metrics and" +
"prestateHash is the hex encoded absolute prestate commitment to use. " +
"If name is omitted the trace type name is used." +
"If the prestateHash is omitted, the absolute prestate hash used for new games on-chain.",
EnvVars: opservice.PrefixEnvVar(flags.EnvVarPrefix, "RUN"),
}
)

func parseRunArgs(args []string) ([]runner.RunConfig, error) {
cfgs := make([]runner.RunConfig, len(args))
for i, arg := range args {
cfg, err := parseRunArg(arg)
if err != nil {
return nil, err
}
cfgs[i] = cfg
}
return cfgs, nil
}

func parseRunArg(arg string) (runner.RunConfig, error) {
cfg := runner.RunConfig{}
opts := strings.SplitN(arg, "/", 3)
if len(opts) == 0 {
return runner.RunConfig{}, fmt.Errorf("invalid run config %q", arg)
}
cfg.TraceType = types.TraceType(opts[0])
if !slices.Contains(types.TraceTypes, cfg.TraceType) {
return runner.RunConfig{}, fmt.Errorf("%w %q for run config %q", ErrUnknownTraceType, opts[0], arg)
}
if len(opts) > 1 {
cfg.Name = opts[1]
} else {
cfg.Name = cfg.TraceType.String()
}
if len(opts) > 2 {
cfg.Prestate = common.HexToHash(opts[2])
if cfg.Prestate == (common.Hash{}) {
return runner.RunConfig{}, fmt.Errorf("%w %q for run config %q", ErrInvalidPrestateHash, opts[2], arg)
}
}
return cfg, nil
}
35 changes: 35 additions & 0 deletions op-challenger/cmd/run_trace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"strings"
"testing"

"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/runner"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)

func TestParseRunArg(t *testing.T) {
tests := []struct {
arg string
expected runner.RunConfig
err error
}{
{arg: "unknown/test1/0x1234", err: ErrUnknownTraceType},
{arg: "cannon", expected: runner.RunConfig{TraceType: types.TraceTypeCannon, Name: types.TraceTypeCannon.String()}},
{arg: "asterisc", expected: runner.RunConfig{TraceType: types.TraceTypeAsterisc, Name: types.TraceTypeAsterisc.String()}},
{arg: "cannon/test1", expected: runner.RunConfig{TraceType: types.TraceTypeCannon, Name: "test1"}},
{arg: "cannon/test1/0x1234", expected: runner.RunConfig{TraceType: types.TraceTypeCannon, Name: "test1", Prestate: common.HexToHash("0x1234")}},
{arg: "cannon/test1/invalid", err: ErrInvalidPrestateHash},
}
for _, test := range tests {
test := test
// Slash characters in test names confuse some things that parse the output as it looks like a subtest
t.Run(strings.ReplaceAll(test.arg, "/", "_"), func(t *testing.T) {
actual, err := parseRunArg(test.arg)
require.ErrorIs(t, err, test.err)
require.Equal(t, test.expected, actual)
})
}
}
22 changes: 0 additions & 22 deletions op-challenger/runner/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,28 +60,6 @@ func createTraceProvider(
return nil, errors.New("invalid trace type")
}

func createMTTraceProvider(
ctx context.Context,
logger log.Logger,
m vm.Metricer,
vmConfig vm.Config,
prestateHash common.Hash,
absolutePrestateBaseURL *url.URL,
localInputs utils.LocalGameInputs,
dir string,
) (types.TraceProvider, error) {
executor := vm.NewOpProgramServerExecutor(logger)
stateConverter := cannon.NewStateConverter(vmConfig)

prestateSource := prestates.NewMultiPrestateProvider(absolutePrestateBaseURL, filepath.Join(dir, "prestates"), stateConverter)
prestatePath, err := prestateSource.PrestatePath(ctx, prestateHash)
if err != nil {
return nil, fmt.Errorf("failed to get prestate %v: %w", prestateHash, err)
}
prestateProvider := vm.NewPrestateProvider(prestatePath, stateConverter)
return cannon.NewTraceProvider(logger, m, vmConfig, executor, prestateProvider, prestatePath, localInputs, dir, 42), nil
}

func getPrestate(ctx context.Context, prestateHash common.Hash, prestateBaseUrl *url.URL, prestatePath string, dataDir string, stateConverter vm.StateConverter) (string, error) {
prestateSource := prestates.NewPrestateSource(
prestateBaseUrl,
Expand Down
Loading

0 comments on commit d41e588

Please sign in to comment.