cmd/evm: make batched state-test execution possible (#27318)
implements the ability to run several state-tests in one instance. By not providing a statetest path to the `evm statetest` command, the path(s) will instead be read from `stdin`.
This commit is contained in:
parent
bfded65ed8
commit
1a18283e85
|
@ -17,8 +17,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import (
|
||||||
var stateTestCommand = &cli.Command{
|
var stateTestCommand = &cli.Command{
|
||||||
Action: stateTestCmd,
|
Action: stateTestCmd,
|
||||||
Name: "statetest",
|
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: "<file>",
|
ArgsUsage: "<file>",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,9 +50,6 @@ type StatetestResult struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func stateTestCmd(ctx *cli.Context) error {
|
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
|
// Configure the go-ethereum logger
|
||||||
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
||||||
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
|
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
|
||||||
|
@ -65,34 +62,43 @@ func stateTestCmd(ctx *cli.Context) error {
|
||||||
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
|
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
|
||||||
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
|
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
|
||||||
}
|
}
|
||||||
var (
|
var cfg vm.Config
|
||||||
tracer vm.EVMLogger
|
|
||||||
debugger *logger.StructLogger
|
|
||||||
)
|
|
||||||
switch {
|
switch {
|
||||||
case ctx.Bool(MachineFlag.Name):
|
case ctx.Bool(MachineFlag.Name):
|
||||||
tracer = logger.NewJSONLogger(config, os.Stderr)
|
cfg.Tracer = logger.NewJSONLogger(config, os.Stderr)
|
||||||
|
|
||||||
case ctx.Bool(DebugFlag.Name):
|
case ctx.Bool(DebugFlag.Name):
|
||||||
debugger = logger.NewStructLogger(config)
|
cfg.Tracer = logger.NewStructLogger(config)
|
||||||
tracer = debugger
|
|
||||||
|
|
||||||
default:
|
|
||||||
debugger = logger.NewStructLogger(config)
|
|
||||||
}
|
}
|
||||||
// Load the test content from the input file
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var tests map[string]tests.StateTest
|
var tests map[string]tests.StateTest
|
||||||
if err = json.Unmarshal(src, &tests); err != nil {
|
if err := json.Unmarshal(src, &tests); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Iterate over all the tests, run them and aggregate the results
|
// Iterate over all the tests, run them and aggregate the results
|
||||||
cfg := vm.Config{
|
|
||||||
Tracer: tracer,
|
|
||||||
}
|
|
||||||
results := make([]StatetestResult, 0, len(tests))
|
results := make([]StatetestResult, 0, len(tests))
|
||||||
for key, test := range tests {
|
for key, test := range tests {
|
||||||
for _, st := range test.Subtests() {
|
for _, st := range test.Subtests() {
|
||||||
|
@ -103,28 +109,20 @@ func stateTestCmd(ctx *cli.Context) error {
|
||||||
if s != nil {
|
if s != nil {
|
||||||
root := s.IntermediateRoot(false)
|
root := s.IntermediateRoot(false)
|
||||||
result.Root = &root
|
result.Root = &root
|
||||||
if ctx.Bool(MachineFlag.Name) {
|
if jsonOut {
|
||||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Test failed, mark as so and dump any state to aid debugging
|
// Test failed, mark as so and dump any state to aid debugging
|
||||||
result.Pass, result.Error = false, err.Error()
|
result.Pass, result.Error = false, err.Error()
|
||||||
if ctx.Bool(DumpFlag.Name) && s != nil {
|
if dump && s != nil {
|
||||||
dump := s.RawDump(nil)
|
dump := s.RawDump(nil)
|
||||||
result.State = &dump
|
result.State = &dump
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, *result)
|
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, "", " ")
|
out, _ := json.MarshalIndent(results, "", " ")
|
||||||
|
|
Loading…
Reference in New Issue