Skip to content

Commit 0ad61af

Browse files
bshastryclaudeMariusVanDerWijdenfjl
committed
cmd/evm: add stdin support to blocktest command (#32824)
Enable blocktest to read filenames from stdin when no path argument is provided, matching the existing statetest behavior. This allows efficient batch processing of blockchain tests. Usage: - Single file: evm blocktest <path> - Batch mode: find tests/ -name "*.json" | evm blocktest --------- Co-authored-by: Claude <[email protected]> Co-authored-by: MariusVanDerWijden <[email protected]> Co-authored-by: Felix Lange <[email protected]>
1 parent 2abb862 commit 0ad61af

File tree

3 files changed

+73
-14
lines changed

3 files changed

+73
-14
lines changed

cmd/evm/blockrunner.go

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,50 +17,71 @@
1717
package main
1818

1919
import (
20+
"bufio"
2021
"encoding/json"
21-
"errors"
2222
"fmt"
2323
"maps"
2424
"os"
2525
"regexp"
2626
"slices"
2727

28+
"github.com/ethereum/go-ethereum/common"
2829
"github.com/ethereum/go-ethereum/core"
2930
"github.com/ethereum/go-ethereum/core/rawdb"
31+
"github.com/ethereum/go-ethereum/log"
3032
"github.com/ethereum/go-ethereum/tests"
3133
"github.com/urfave/cli/v2"
3234
)
3335

3436
var blockTestCommand = &cli.Command{
3537
Action: blockTestCmd,
3638
Name: "blocktest",
37-
Usage: "Executes the given blockchain tests",
39+
Usage: "Executes the given blockchain tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).",
3840
ArgsUsage: "<path>",
3941
Flags: slices.Concat([]cli.Flag{
4042
DumpFlag,
4143
HumanReadableFlag,
4244
RunFlag,
4345
WitnessCrossCheckFlag,
46+
FuzzFlag,
4447
}, traceFlags),
4548
}
4649

4750
func blockTestCmd(ctx *cli.Context) error {
4851
path := ctx.Args().First()
49-
if len(path) == 0 {
50-
return errors.New("path argument required")
52+
53+
// If path is provided, run the tests at that path.
54+
if len(path) != 0 {
55+
var (
56+
collected = collectFiles(path)
57+
results []testResult
58+
)
59+
for _, fname := range collected {
60+
r, err := runBlockTest(ctx, fname)
61+
if err != nil {
62+
return err
63+
}
64+
results = append(results, r...)
65+
}
66+
report(ctx, results)
67+
return nil
5168
}
52-
var (
53-
collected = collectFiles(path)
54-
results []testResult
55-
)
56-
for _, fname := range collected {
57-
r, err := runBlockTest(ctx, fname)
69+
// Otherwise, read filenames from stdin and execute back-to-back.
70+
scanner := bufio.NewScanner(os.Stdin)
71+
for scanner.Scan() {
72+
fname := scanner.Text()
73+
if len(fname) == 0 {
74+
return nil
75+
}
76+
results, err := runBlockTest(ctx, fname)
5877
if err != nil {
5978
return err
6079
}
61-
results = append(results, r...)
80+
// During fuzzing, we report the result after every block
81+
if !ctx.IsSet(FuzzFlag.Name) {
82+
report(ctx, results)
83+
}
6284
}
63-
report(ctx, results)
6485
return nil
6586
}
6687

@@ -79,6 +100,11 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) {
79100
}
80101
tracer := tracerFromFlags(ctx)
81102

103+
// Suppress INFO logs during fuzzing
104+
if ctx.IsSet(FuzzFlag.Name) {
105+
log.SetDefault(log.NewLogger(log.DiscardHandler()))
106+
}
107+
82108
// Pull out keys to sort and ensure tests are run in order.
83109
keys := slices.Sorted(maps.Keys(tests))
84110

@@ -88,16 +114,35 @@ func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) {
88114
if !re.MatchString(name) {
89115
continue
90116
}
117+
test := tests[name]
91118
result := &testResult{Name: name, Pass: true}
92-
if err := tests[name].Run(false, rawdb.PathScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) {
119+
var finalRoot *common.Hash
120+
if err := test.Run(false, rawdb.PathScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) {
93121
if ctx.Bool(DumpFlag.Name) {
94122
if s, _ := chain.State(); s != nil {
95123
result.State = dump(s)
96124
}
97125
}
126+
// Capture final state root for end marker
127+
if chain != nil {
128+
root := chain.CurrentBlock().Root
129+
finalRoot = &root
130+
}
98131
}); err != nil {
99132
result.Pass, result.Error = false, err.Error()
100133
}
134+
135+
// Always assign fork (regardless of pass/fail or tracer)
136+
result.Fork = test.Network()
137+
// Assign root if test succeeded
138+
if result.Pass && finalRoot != nil {
139+
result.Root = finalRoot
140+
}
141+
142+
// When fuzzing, write results after every block
143+
if ctx.IsSet(FuzzFlag.Name) {
144+
report(ctx, []testResult{*result})
145+
}
101146
results = append(results, *result)
102147
}
103148
return results, nil

cmd/evm/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ var (
5555
Usage: "benchmark the execution",
5656
Category: flags.VMCategory,
5757
}
58+
FuzzFlag = &cli.BoolFlag{
59+
Name: "fuzz",
60+
Usage: "adapts output format for fuzzing",
61+
Category: flags.VMCategory,
62+
}
5863
WitnessCrossCheckFlag = &cli.BoolFlag{
5964
Name: "cross-check",
6065
Aliases: []string{"xc"},

tests/block_test_util.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t
116116
if !ok {
117117
return UnsupportedForkError{t.json.Network}
118118
}
119+
return t.run(config, snapshotter, scheme, witness, tracer, postCheck)
120+
}
121+
122+
// Network returns the network/fork name for this test.
123+
func (t *BlockTest) Network() string {
124+
return t.json.Network
125+
}
126+
127+
func (t *BlockTest) run(config *params.ChainConfig, snapshotter bool, scheme string, witness bool, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) {
119128
// import pre accounts & construct test genesis block & state root
120129
// Commit genesis state
121130
var (
@@ -260,7 +269,7 @@ func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error)
260269
}
261270
if b.BlockHeader == nil {
262271
if data, err := json.MarshalIndent(cb.Header(), "", " "); err == nil {
263-
fmt.Fprintf(os.Stderr, "block (index %d) insertion should have failed due to: %v:\n%v\n",
272+
fmt.Fprintf(os.Stdout, "block (index %d) insertion should have failed due to: %v:\n%v\n",
264273
bi, b.ExpectException, string(data))
265274
}
266275
return nil, fmt.Errorf("block (index %d) insertion should have failed due to: %v",

0 commit comments

Comments
 (0)