diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index e9229eaeca..ed102e6054 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -17,8 +17,8 @@ package main import ( + "bufio" "encoding/json" - "errors" "fmt" "os" @@ -34,7 +34,7 @@ import ( var stateTestCommand = &cli.Command{ Action: stateTestCmd, Name: "statetest", - Usage: "executes the given state tests", + Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).", ArgsUsage: "", } @@ -50,9 +50,6 @@ type StatetestResult struct { } func stateTestCmd(ctx *cli.Context) error { - if len(ctx.Args().First()) == 0 { - return errors.New("path-to-test argument required") - } // Configure the go-ethereum logger glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) @@ -65,34 +62,43 @@ func stateTestCmd(ctx *cli.Context) error { DisableStorage: ctx.Bool(DisableStorageFlag.Name), EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), } - var ( - tracer vm.EVMLogger - debugger *logger.StructLogger - ) + var cfg vm.Config switch { case ctx.Bool(MachineFlag.Name): - tracer = logger.NewJSONLogger(config, os.Stderr) + cfg.Tracer = logger.NewJSONLogger(config, os.Stderr) case ctx.Bool(DebugFlag.Name): - debugger = logger.NewStructLogger(config) - tracer = debugger - - default: - debugger = logger.NewStructLogger(config) + cfg.Tracer = logger.NewStructLogger(config) } // Load the test content from the input file - src, err := os.ReadFile(ctx.Args().First()) + if len(ctx.Args().First()) != 0 { + return runStateTest(ctx.Args().First(), cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name)) + } + // Read filenames from stdin and execute back-to-back + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + fname := scanner.Text() + if len(fname) == 0 { + return nil + } + if err := runStateTest(fname, cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name)); err != nil { + return err + } + } + return nil +} + +// runStateTest loads the state-test given by fname, and executes the test. +func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error { + src, err := os.ReadFile(fname) if err != nil { return err } var tests map[string]tests.StateTest - if err = json.Unmarshal(src, &tests); err != nil { + if err := json.Unmarshal(src, &tests); err != nil { return err } // Iterate over all the tests, run them and aggregate the results - cfg := vm.Config{ - Tracer: tracer, - } results := make([]StatetestResult, 0, len(tests)) for key, test := range tests { for _, st := range test.Subtests() { @@ -103,28 +109,20 @@ func stateTestCmd(ctx *cli.Context) error { if s != nil { root := s.IntermediateRoot(false) result.Root = &root - if ctx.Bool(MachineFlag.Name) { + if jsonOut { fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) } } if err != nil { // Test failed, mark as so and dump any state to aid debugging result.Pass, result.Error = false, err.Error() - if ctx.Bool(DumpFlag.Name) && s != nil { + if dump && s != nil { dump := s.RawDump(nil) result.State = &dump } } results = append(results, *result) - - // Print any structured logs collected - if ctx.Bool(DebugFlag.Name) { - if debugger != nil { - fmt.Fprintln(os.Stderr, "#### TRACE ####") - logger.WriteTrace(os.Stderr, debugger.StructLogs()) - } - } } } out, _ := json.MarshalIndent(results, "", " ")