@@ -20,9 +20,16 @@ import (
20
20
"bufio"
21
21
"bytes"
22
22
"fmt"
23
+ "math/big"
24
+ "os"
25
+ "path/filepath"
23
26
"reflect"
27
+ "strings"
24
28
"testing"
25
29
30
+ "github.com/ethereum/go-ethereum/core"
31
+ "github.com/ethereum/go-ethereum/core/rawdb"
32
+ "github.com/ethereum/go-ethereum/core/types"
26
33
"github.com/ethereum/go-ethereum/core/vm"
27
34
"github.com/ethereum/go-ethereum/eth/tracers/logger"
28
35
)
@@ -61,6 +68,7 @@ func TestState(t *testing.T) {
61
68
for _ , dir := range []string {
62
69
stateTestDir ,
63
70
legacyStateTestDir ,
71
+ benchmarksDir ,
64
72
} {
65
73
st .walk (t , dir , func (t * testing.T , name string , test * StateTest ) {
66
74
for _ , subtest := range test .Subtests () {
@@ -131,3 +139,116 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) {
131
139
// t.Logf("EVM output: 0x%x", tracer.Output())
132
140
// t.Logf("EVM error: %v", tracer.Error())
133
141
}
142
+
143
+ func BenchmarkEVM (b * testing.B ) {
144
+ // Walk the directory.
145
+ dir := benchmarksDir
146
+ dirinfo , err := os .Stat (dir )
147
+ if os .IsNotExist (err ) || ! dirinfo .IsDir () {
148
+ fmt .Fprintf (os .Stderr , "can't find test files in %s, did you clone the evm-benchmarks submodule?\n " , dir )
149
+ b .Skip ("missing test files" )
150
+ }
151
+ err = filepath .Walk (dir , func (path string , info os.FileInfo , err error ) error {
152
+ if info .IsDir () {
153
+ return nil
154
+ }
155
+ if ext := filepath .Ext (path ); ext == ".json" {
156
+ name := filepath .ToSlash (strings .TrimPrefix (strings .TrimSuffix (path , ext ), dir + string (filepath .Separator )))
157
+ b .Run (name , func (b * testing.B ) { runBenchmarkFile (b , path ) })
158
+ }
159
+ return nil
160
+ })
161
+ if err != nil {
162
+ b .Fatal (err )
163
+ }
164
+ }
165
+
166
+ func runBenchmarkFile (b * testing.B , path string ) {
167
+ m := make (map [string ]StateTest )
168
+ if err := readJSONFile (path , & m ); err != nil {
169
+ b .Fatal (err )
170
+ return
171
+ }
172
+ if len (m ) != 1 {
173
+ b .Fatal ("expected single benchmark in a file" )
174
+ return
175
+ }
176
+ for _ , t := range m {
177
+ runBenchmark (b , & t )
178
+ }
179
+ }
180
+
181
+ func runBenchmark (b * testing.B , t * StateTest ) {
182
+ for _ , subtest := range t .Subtests () {
183
+ subtest := subtest
184
+ key := fmt .Sprintf ("%s/%d" , subtest .Fork , subtest .Index )
185
+
186
+ b .Run (key , func (b * testing.B ) {
187
+ vmconfig := vm.Config {}
188
+
189
+ config , eips , err := GetChainConfig (subtest .Fork )
190
+ if err != nil {
191
+ b .Error (err )
192
+ return
193
+ }
194
+ vmconfig .ExtraEips = eips
195
+ block := t .genesis (config ).ToBlock (nil )
196
+ _ , statedb := MakePreState (rawdb .NewMemoryDatabase (), t .json .Pre , false )
197
+
198
+ var baseFee * big.Int
199
+ if config .IsLondon (new (big.Int )) {
200
+ baseFee = t .json .Env .BaseFee
201
+ if baseFee == nil {
202
+ // Retesteth uses `0x10` for genesis baseFee. Therefore, it defaults to
203
+ // parent - 2 : 0xa as the basefee for 'this' context.
204
+ baseFee = big .NewInt (0x0a )
205
+ }
206
+ }
207
+ post := t .json .Post [subtest .Fork ][subtest .Index ]
208
+ msg , err := t .json .Tx .toMessage (post , baseFee )
209
+ if err != nil {
210
+ b .Error (err )
211
+ return
212
+ }
213
+
214
+ // Try to recover tx with current signer
215
+ if len (post .TxBytes ) != 0 {
216
+ var ttx types.Transaction
217
+ err := ttx .UnmarshalBinary (post .TxBytes )
218
+ if err != nil {
219
+ b .Error (err )
220
+ return
221
+ }
222
+
223
+ if _ , err := types .Sender (types .LatestSigner (config ), & ttx ); err != nil {
224
+ b .Error (err )
225
+ return
226
+ }
227
+ }
228
+
229
+ // Prepare the EVM.
230
+ txContext := core .NewEVMTxContext (msg )
231
+ context := core .NewEVMBlockContext (block .Header (), nil , & t .json .Env .Coinbase )
232
+ context .GetHash = vmTestBlockHash
233
+ context .BaseFee = baseFee
234
+ evm := vm .NewEVM (context , txContext , statedb , config , vmconfig )
235
+
236
+ // Create "contract" for sender to cache code analysis.
237
+ sender := vm .NewContract (vm .AccountRef (msg .From ()), vm .AccountRef (msg .From ()),
238
+ nil , 0 )
239
+
240
+ b .ResetTimer ()
241
+ for n := 0 ; n < b .N ; n ++ {
242
+ // Execute the message.
243
+ snapshot := statedb .Snapshot ()
244
+ _ , _ , err = evm .Call (sender , * msg .To (), msg .Data (), msg .Gas (), msg .Value ())
245
+ if err != nil {
246
+ b .Error (err )
247
+ return
248
+ }
249
+ statedb .RevertToSnapshot (snapshot )
250
+ }
251
+
252
+ })
253
+ }
254
+ }
0 commit comments