@@ -27,26 +27,51 @@ import (
27
27
"github.com/ethereum/go-ethereum/core/state"
28
28
"github.com/ethereum/go-ethereum/core/vm"
29
29
"github.com/ethereum/go-ethereum/eth/tracers/logger"
30
+ "github.com/ethereum/go-ethereum/internal/flags"
30
31
"github.com/ethereum/go-ethereum/tests"
31
32
"github.com/urfave/cli/v2"
32
33
)
33
34
35
+ var (
36
+ forkFlag = & cli.StringFlag {
37
+ Name : "statetest.fork" ,
38
+ Usage : "The hard-fork to run the test against" ,
39
+ Category : flags .VMCategory ,
40
+ }
41
+ idxFlag = & cli.IntFlag {
42
+ Name : "statetest.index" ,
43
+ Usage : "The index of the subtest to run" ,
44
+ Category : flags .VMCategory ,
45
+ Value : - 1 , // default to select all subtest indices
46
+ }
47
+ testNameFlag = & cli.StringFlag {
48
+ Name : "statetest.name" ,
49
+ Usage : "The name of the state test to run" ,
50
+ Category : flags .VMCategory ,
51
+ }
52
+ )
34
53
var stateTestCommand = & cli.Command {
35
54
Action : stateTestCmd ,
36
55
Name : "statetest" ,
37
56
Usage : "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution)." ,
38
57
ArgsUsage : "<file>" ,
58
+ Flags : []cli.Flag {
59
+ forkFlag ,
60
+ idxFlag ,
61
+ testNameFlag ,
62
+ },
39
63
}
40
64
41
65
// StatetestResult contains the execution status after running a state test, any
42
66
// error that might have occurred and a dump of the final state if requested.
43
67
type StatetestResult struct {
44
- Name string `json:"name"`
45
- Pass bool `json:"pass"`
46
- Root * common.Hash `json:"stateRoot,omitempty"`
47
- Fork string `json:"fork"`
48
- Error string `json:"error,omitempty"`
49
- State * state.Dump `json:"state,omitempty"`
68
+ Name string `json:"name"`
69
+ Pass bool `json:"pass"`
70
+ Root * common.Hash `json:"stateRoot,omitempty"`
71
+ Fork string `json:"fork"`
72
+ Error string `json:"error,omitempty"`
73
+ State * state.Dump `json:"state,omitempty"`
74
+ BenchStats * execStats `json:"benchStats,omitempty"`
50
75
}
51
76
52
77
func stateTestCmd (ctx * cli.Context ) error {
@@ -67,7 +92,7 @@ func stateTestCmd(ctx *cli.Context) error {
67
92
}
68
93
// Load the test content from the input file
69
94
if len (ctx .Args ().First ()) != 0 {
70
- return runStateTest (ctx .Args ().First (), cfg , ctx .Bool (DumpFlag .Name ))
95
+ return runStateTest (ctx , ctx .Args ().First (), cfg , ctx .Bool (DumpFlag . Name ), ctx . Bool ( BenchFlag .Name ))
71
96
}
72
97
// Read filenames from stdin and execute back-to-back
73
98
scanner := bufio .NewScanner (os .Stdin )
@@ -76,15 +101,48 @@ func stateTestCmd(ctx *cli.Context) error {
76
101
if len (fname ) == 0 {
77
102
return nil
78
103
}
79
- if err := runStateTest (fname , cfg , ctx .Bool (DumpFlag .Name )); err != nil {
104
+ if err := runStateTest (ctx , fname , cfg , ctx .Bool (DumpFlag . Name ), ctx . Bool ( BenchFlag .Name )); err != nil {
80
105
return err
81
106
}
82
107
}
83
108
return nil
84
109
}
85
110
111
+ type stateTestCase struct {
112
+ name string
113
+ test tests.StateTest
114
+ st tests.StateSubtest
115
+ }
116
+
117
+ // collectMatchedSubtests returns test cases which match against provided filtering CLI parameters
118
+ func collectMatchedSubtests (ctx * cli.Context , testsByName map [string ]tests.StateTest ) []stateTestCase {
119
+ var res []stateTestCase
120
+ subtestName := ctx .String (testNameFlag .Name )
121
+ if subtestName != "" {
122
+ if subtest , ok := testsByName [subtestName ]; ok {
123
+ testsByName := make (map [string ]tests.StateTest )
124
+ testsByName [subtestName ] = subtest
125
+ }
126
+ }
127
+ idx := ctx .Int (idxFlag .Name )
128
+ fork := ctx .String (forkFlag .Name )
129
+
130
+ for key , test := range testsByName {
131
+ for _ , st := range test .Subtests () {
132
+ if idx != - 1 && st .Index != idx {
133
+ continue
134
+ }
135
+ if fork != "" && st .Fork != fork {
136
+ continue
137
+ }
138
+ res = append (res , stateTestCase {name : key , st : st , test : test })
139
+ }
140
+ }
141
+ return res
142
+ }
143
+
86
144
// runStateTest loads the state-test given by fname, and executes the test.
87
- func runStateTest (fname string , cfg vm.Config , dump bool ) error {
145
+ func runStateTest (ctx * cli. Context , fname string , cfg vm.Config , dump bool , bench bool ) error {
88
146
src , err := os .ReadFile (fname )
89
147
if err != nil {
90
148
return err
@@ -94,31 +152,38 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
94
152
return err
95
153
}
96
154
155
+ matchingTests := collectMatchedSubtests (ctx , testsByName )
156
+
97
157
// Iterate over all the tests, run them and aggregate the results
98
- results := make ([]StatetestResult , 0 , len (testsByName ))
99
- for key , test := range testsByName {
100
- for _ , st := range test .Subtests () {
101
- // Run the test and aggregate the result
102
- result := & StatetestResult {Name : key , Fork : st .Fork , Pass : true }
103
- test .Run (st , cfg , false , rawdb .HashScheme , func (err error , tstate * tests.StateTestState ) {
104
- var root common.Hash
105
- if tstate .StateDB != nil {
106
- root = tstate .StateDB .IntermediateRoot (false )
107
- result .Root = & root
108
- fmt .Fprintf (os .Stderr , "{\" stateRoot\" : \" %#x\" }\n " , root )
109
- if dump { // Dump any state to aid debugging
110
- cpy , _ := state .New (root , tstate .StateDB .Database ())
111
- dump := cpy .RawDump (nil )
112
- result .State = & dump
113
- }
114
- }
115
- if err != nil {
116
- // Test failed, mark as so
117
- result .Pass , result .Error = false , err .Error ()
158
+ var results []StatetestResult
159
+ for _ , test := range matchingTests {
160
+ // Run the test and aggregate the result
161
+ result := & StatetestResult {Name : test .name , Fork : test .st .Fork , Pass : true }
162
+ test .test .Run (test .st , cfg , false , rawdb .HashScheme , func (err error , tstate * tests.StateTestState ) {
163
+ var root common.Hash
164
+ if tstate .StateDB != nil {
165
+ root = tstate .StateDB .IntermediateRoot (false )
166
+ result .Root = & root
167
+ fmt .Fprintf (os .Stderr , "{\" stateRoot\" : \" %#x\" }\n " , root )
168
+ if dump { // Dump any state to aid debugging
169
+ cpy , _ := state .New (root , tstate .StateDB .Database ())
170
+ dump := cpy .RawDump (nil )
171
+ result .State = & dump
118
172
}
173
+ }
174
+ if err != nil {
175
+ // Test failed, mark as so
176
+ result .Pass , result .Error = false , err .Error ()
177
+ }
178
+ })
179
+ if bench {
180
+ _ , stats , _ := timedExec (true , func () ([]byte , uint64 , error ) {
181
+ _ , _ , gasUsed , _ := test .test .RunNoVerify (test .st , cfg , false , rawdb .HashScheme )
182
+ return nil , gasUsed , nil
119
183
})
120
- results = append ( results , * result )
184
+ result . BenchStats = & stats
121
185
}
186
+ results = append (results , * result )
122
187
}
123
188
out , _ := json .MarshalIndent (results , "" , " " )
124
189
fmt .Println (string (out ))
0 commit comments