mirror of https://github.com/ethereum/go-ethereum
cmd/evm: improve block/state test runner (#30633)
* unify `staterunner` and `blockrunner` CLI flags, especially around tracing * added support for struct logger or json logging (although having issue #30658) * new --cross-check flag to validate the stateless witness collection / execution matches stateful * adds support for tracing the stateless execution when a tracer is set (to more easily debug differences) * --human for more readable test summary * directory or file input, so if you pass tests/spec-tests/fixtures/blockchain_tests it will execute all blockchain testspull/30846/head
parent
ce8cec007c
commit
5347280319
@ -1,55 +0,0 @@ |
||||
// Copyright 2017 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"os" |
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" |
||||
|
||||
"github.com/urfave/cli/v2" |
||||
) |
||||
|
||||
var compileCommand = &cli.Command{ |
||||
Action: compileCmd, |
||||
Name: "compile", |
||||
Usage: "Compiles easm source to evm binary", |
||||
ArgsUsage: "<file>", |
||||
} |
||||
|
||||
func compileCmd(ctx *cli.Context) error { |
||||
debug := ctx.Bool(DebugFlag.Name) |
||||
|
||||
if len(ctx.Args().First()) == 0 { |
||||
return errors.New("filename required") |
||||
} |
||||
|
||||
fn := ctx.Args().First() |
||||
src, err := os.ReadFile(fn) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
bin, err := compiler.Compile(fn, src, debug) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
fmt.Println(bin) |
||||
return nil |
||||
} |
@ -1,55 +0,0 @@ |
||||
// Copyright 2017 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"os" |
||||
"strings" |
||||
|
||||
"github.com/ethereum/go-ethereum/core/asm" |
||||
"github.com/urfave/cli/v2" |
||||
) |
||||
|
||||
var disasmCommand = &cli.Command{ |
||||
Action: disasmCmd, |
||||
Name: "disasm", |
||||
Usage: "Disassembles evm binary", |
||||
ArgsUsage: "<file>", |
||||
} |
||||
|
||||
func disasmCmd(ctx *cli.Context) error { |
||||
var in string |
||||
switch { |
||||
case len(ctx.Args().First()) > 0: |
||||
fn := ctx.Args().First() |
||||
input, err := os.ReadFile(fn) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
in = string(input) |
||||
case ctx.IsSet(InputFlag.Name): |
||||
in = ctx.String(InputFlag.Name) |
||||
default: |
||||
return errors.New("missing filename or --input value") |
||||
} |
||||
|
||||
code := strings.TrimSpace(in) |
||||
fmt.Printf("%v\n", code) |
||||
return asm.PrintDisassembled(code) |
||||
} |
@ -0,0 +1,49 @@ |
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main |
||||
|
||||
import "regexp" |
||||
|
||||
// testMetadata provides more granular access to the test information encoded
|
||||
// within its filename by the execution spec test (EEST).
|
||||
type testMetadata struct { |
||||
fork string |
||||
module string // which python module gnerated the test, e.g. eip7702
|
||||
file string // exact file the test came from, e.g. test_gas.py
|
||||
function string // func that created the test, e.g. test_valid_mcopy_operations
|
||||
parameters string // the name of the parameters which were used to fill the test, e.g. zero_inputs
|
||||
} |
||||
|
||||
// parseTestMetadata reads a test name and parses out more specific information
|
||||
// about the test.
|
||||
func parseTestMetadata(s string) *testMetadata { |
||||
var ( |
||||
pattern = `tests\/([^\/]+)\/([^\/]+)\/([^:]+)::([^[]+)\[fork_([^-\]]+)-[^-]+-(.+)\]` |
||||
re = regexp.MustCompile(pattern) |
||||
) |
||||
match := re.FindStringSubmatch(s) |
||||
if len(match) == 0 { |
||||
return nil |
||||
} |
||||
return &testMetadata{ |
||||
fork: match[5], |
||||
module: match[2], |
||||
file: match[3], |
||||
function: match[4], |
||||
parameters: match[6], |
||||
} |
||||
} |
@ -1,39 +0,0 @@ |
||||
// Copyright 2017 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package compiler |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
|
||||
"github.com/ethereum/go-ethereum/core/asm" |
||||
) |
||||
|
||||
func Compile(fn string, src []byte, debug bool) (string, error) { |
||||
compiler := asm.NewCompiler(debug) |
||||
compiler.Feed(asm.Lex(src, debug)) |
||||
|
||||
bin, compileErrors := compiler.Compile() |
||||
if len(compileErrors) > 0 { |
||||
// report errors
|
||||
for _, err := range compileErrors { |
||||
fmt.Printf("%s:%v\n", fn, err) |
||||
} |
||||
return "", errors.New("compiling failed") |
||||
} |
||||
return bin, nil |
||||
} |
@ -0,0 +1,87 @@ |
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/urfave/cli/v2" |
||||
) |
||||
|
||||
const ( |
||||
PASS = "\033[32mPASS\033[0m" |
||||
FAIL = "\033[31mFAIL\033[0m" |
||||
) |
||||
|
||||
// testResult contains the execution status after running a state test, any
|
||||
// error that might have occurred and a dump of the final state if requested.
|
||||
type testResult struct { |
||||
Name string `json:"name"` |
||||
Pass bool `json:"pass"` |
||||
Root *common.Hash `json:"stateRoot,omitempty"` |
||||
Fork string `json:"fork"` |
||||
Error string `json:"error,omitempty"` |
||||
State *state.Dump `json:"state,omitempty"` |
||||
Stats *execStats `json:"benchStats,omitempty"` |
||||
} |
||||
|
||||
func (r testResult) String() string { |
||||
var status string |
||||
if r.Pass { |
||||
status = fmt.Sprintf("[%s]", PASS) |
||||
} else { |
||||
status = fmt.Sprintf("[%s]", FAIL) |
||||
} |
||||
info := r.Name |
||||
m := parseTestMetadata(r.Name) |
||||
if m != nil { |
||||
info = fmt.Sprintf("%s %s, param=%s", m.module, m.function, m.parameters) |
||||
} |
||||
var extra string |
||||
if !r.Pass { |
||||
extra = fmt.Sprintf(", err=%v, fork=%s", r.Error, r.Fork) |
||||
} |
||||
out := fmt.Sprintf("%s %s%s", status, info, extra) |
||||
if r.State != nil { |
||||
state, _ := json.MarshalIndent(r.State, "", " ") |
||||
out += "\n" + string(state) |
||||
} |
||||
return out |
||||
} |
||||
|
||||
// report prints the after-test summary.
|
||||
func report(ctx *cli.Context, results []testResult) { |
||||
if ctx.Bool(HumanReadableFlag.Name) { |
||||
pass := 0 |
||||
for _, r := range results { |
||||
if r.Pass { |
||||
pass++ |
||||
} |
||||
} |
||||
for _, r := range results { |
||||
fmt.Println(r) |
||||
} |
||||
fmt.Println("--") |
||||
fmt.Printf("%d tests passed, %d tests failed.\n", pass, len(results)-pass) |
||||
return |
||||
} |
||||
out, _ := json.MarshalIndent(results, "", " ") |
||||
fmt.Println(string(out)) |
||||
} |
Loading…
Reference in new issue