@@ -27,26 +27,51 @@ import (
2727 "github.com/ethereum/go-ethereum/core/state"
2828 "github.com/ethereum/go-ethereum/core/vm"
2929 "github.com/ethereum/go-ethereum/eth/tracers/logger"
30+ "github.com/ethereum/go-ethereum/internal/flags"
3031 "github.com/ethereum/go-ethereum/tests"
3132 "github.com/urfave/cli/v2"
3233)
3334
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+ )
3453var stateTestCommand = & cli.Command {
3554 Action : stateTestCmd ,
3655 Name : "statetest" ,
3756 Usage : "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution)." ,
3857 ArgsUsage : "<file>" ,
58+ Flags : []cli.Flag {
59+ forkFlag ,
60+ idxFlag ,
61+ testNameFlag ,
62+ },
3963}
4064
4165// StatetestResult contains the execution status after running a state test, any
4266// error that might have occurred and a dump of the final state if requested.
4367type 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"`
5075}
5176
5277func stateTestCmd (ctx * cli.Context ) error {
@@ -67,7 +92,7 @@ func stateTestCmd(ctx *cli.Context) error {
6792 }
6893 // Load the test content from the input file
6994 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 ))
7196 }
7297 // Read filenames from stdin and execute back-to-back
7398 scanner := bufio .NewScanner (os .Stdin )
@@ -76,15 +101,48 @@ func stateTestCmd(ctx *cli.Context) error {
76101 if len (fname ) == 0 {
77102 return nil
78103 }
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 {
80105 return err
81106 }
82107 }
83108 return nil
84109}
85110
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+
86144// 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 {
88146 src , err := os .ReadFile (fname )
89147 if err != nil {
90148 return err
@@ -94,31 +152,38 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
94152 return err
95153 }
96154
155+ matchingTests := collectMatchedSubtests (ctx , testsByName )
156+
97157 // 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
118172 }
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
119183 })
120- results = append ( results , * result )
184+ result . BenchStats = & stats
121185 }
186+ results = append (results , * result )
122187 }
123188 out , _ := json .MarshalIndent (results , "" , " " )
124189 fmt .Println (string (out ))
0 commit comments