Skip to content

Commit 64c53ed

Browse files
authored
tests: external evm benchmarks (#24050)
* tests: add ipsilon/evm-benchmarks git submodule * tests: plug-in evm-benchmarks
1 parent abd49a6 commit 64c53ed

File tree

4 files changed

+127
-0
lines changed

4 files changed

+127
-0
lines changed

.gitmodules

+4
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22
path = tests/testdata
33
url = https://github.com/ethereum/tests
44
shallow = true
5+
[submodule "evm-benchmarks"]
6+
path = tests/evm-benchmarks
7+
url = https://github.com/ipsilon/evm-benchmarks
8+
shallow = true

tests/evm-benchmarks

Submodule evm-benchmarks added at 849b3e2

tests/init_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ var (
4141
transactionTestDir = filepath.Join(baseDir, "TransactionTests")
4242
rlpTestDir = filepath.Join(baseDir, "RLPTests")
4343
difficultyTestDir = filepath.Join(baseDir, "BasicTests")
44+
benchmarksDir = filepath.Join(".", "evm-benchmarks", "benchmarks")
4445
)
4546

4647
func readJSON(reader io.Reader, value interface{}) error {

tests/state_test.go

+121
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,16 @@ import (
2020
"bufio"
2121
"bytes"
2222
"fmt"
23+
"math/big"
24+
"os"
25+
"path/filepath"
2326
"reflect"
27+
"strings"
2428
"testing"
2529

30+
"github.com/ethereum/go-ethereum/core"
31+
"github.com/ethereum/go-ethereum/core/rawdb"
32+
"github.com/ethereum/go-ethereum/core/types"
2633
"github.com/ethereum/go-ethereum/core/vm"
2734
"github.com/ethereum/go-ethereum/eth/tracers/logger"
2835
)
@@ -61,6 +68,7 @@ func TestState(t *testing.T) {
6168
for _, dir := range []string{
6269
stateTestDir,
6370
legacyStateTestDir,
71+
benchmarksDir,
6472
} {
6573
st.walk(t, dir, func(t *testing.T, name string, test *StateTest) {
6674
for _, subtest := range test.Subtests() {
@@ -131,3 +139,116 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) {
131139
// t.Logf("EVM output: 0x%x", tracer.Output())
132140
// t.Logf("EVM error: %v", tracer.Error())
133141
}
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

Comments
 (0)