tests: external evm benchmarks (#24050)
* tests: add ipsilon/evm-benchmarks git submodule * tests: plug-in evm-benchmarks
This commit is contained in:
parent
abd49a6c48
commit
64c53edf83
|
@ -2,3 +2,7 @@
|
||||||
path = tests/testdata
|
path = tests/testdata
|
||||||
url = https://github.com/ethereum/tests
|
url = https://github.com/ethereum/tests
|
||||||
shallow = true
|
shallow = true
|
||||||
|
[submodule "evm-benchmarks"]
|
||||||
|
path = tests/evm-benchmarks
|
||||||
|
url = https://github.com/ipsilon/evm-benchmarks
|
||||||
|
shallow = true
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 849b3e239a28f236dc99574b2e10e0c720895105
|
|
@ -41,6 +41,7 @@ var (
|
||||||
transactionTestDir = filepath.Join(baseDir, "TransactionTests")
|
transactionTestDir = filepath.Join(baseDir, "TransactionTests")
|
||||||
rlpTestDir = filepath.Join(baseDir, "RLPTests")
|
rlpTestDir = filepath.Join(baseDir, "RLPTests")
|
||||||
difficultyTestDir = filepath.Join(baseDir, "BasicTests")
|
difficultyTestDir = filepath.Join(baseDir, "BasicTests")
|
||||||
|
benchmarksDir = filepath.Join(".", "evm-benchmarks", "benchmarks")
|
||||||
)
|
)
|
||||||
|
|
||||||
func readJSON(reader io.Reader, value interface{}) error {
|
func readJSON(reader io.Reader, value interface{}) error {
|
||||||
|
|
|
@ -20,9 +20,16 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
)
|
)
|
||||||
|
@ -61,6 +68,7 @@ func TestState(t *testing.T) {
|
||||||
for _, dir := range []string{
|
for _, dir := range []string{
|
||||||
stateTestDir,
|
stateTestDir,
|
||||||
legacyStateTestDir,
|
legacyStateTestDir,
|
||||||
|
benchmarksDir,
|
||||||
} {
|
} {
|
||||||
st.walk(t, dir, func(t *testing.T, name string, test *StateTest) {
|
st.walk(t, dir, func(t *testing.T, name string, test *StateTest) {
|
||||||
for _, subtest := range test.Subtests() {
|
for _, subtest := range test.Subtests() {
|
||||||
|
@ -131,3 +139,116 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) {
|
||||||
// t.Logf("EVM output: 0x%x", tracer.Output())
|
// t.Logf("EVM output: 0x%x", tracer.Output())
|
||||||
// t.Logf("EVM error: %v", tracer.Error())
|
// t.Logf("EVM error: %v", tracer.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkEVM(b *testing.B) {
|
||||||
|
// Walk the directory.
|
||||||
|
dir := benchmarksDir
|
||||||
|
dirinfo, err := os.Stat(dir)
|
||||||
|
if os.IsNotExist(err) || !dirinfo.IsDir() {
|
||||||
|
fmt.Fprintf(os.Stderr, "can't find test files in %s, did you clone the evm-benchmarks submodule?\n", dir)
|
||||||
|
b.Skip("missing test files")
|
||||||
|
}
|
||||||
|
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ext := filepath.Ext(path); ext == ".json" {
|
||||||
|
name := filepath.ToSlash(strings.TrimPrefix(strings.TrimSuffix(path, ext), dir+string(filepath.Separator)))
|
||||||
|
b.Run(name, func(b *testing.B) { runBenchmarkFile(b, path) })
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runBenchmarkFile(b *testing.B, path string) {
|
||||||
|
m := make(map[string]StateTest)
|
||||||
|
if err := readJSONFile(path, &m); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(m) != 1 {
|
||||||
|
b.Fatal("expected single benchmark in a file")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, t := range m {
|
||||||
|
runBenchmark(b, &t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runBenchmark(b *testing.B, t *StateTest) {
|
||||||
|
for _, subtest := range t.Subtests() {
|
||||||
|
subtest := subtest
|
||||||
|
key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index)
|
||||||
|
|
||||||
|
b.Run(key, func(b *testing.B) {
|
||||||
|
vmconfig := vm.Config{}
|
||||||
|
|
||||||
|
config, eips, err := GetChainConfig(subtest.Fork)
|
||||||
|
if err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vmconfig.ExtraEips = eips
|
||||||
|
block := t.genesis(config).ToBlock(nil)
|
||||||
|
_, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, false)
|
||||||
|
|
||||||
|
var baseFee *big.Int
|
||||||
|
if config.IsLondon(new(big.Int)) {
|
||||||
|
baseFee = t.json.Env.BaseFee
|
||||||
|
if baseFee == nil {
|
||||||
|
// Retesteth uses `0x10` for genesis baseFee. Therefore, it defaults to
|
||||||
|
// parent - 2 : 0xa as the basefee for 'this' context.
|
||||||
|
baseFee = big.NewInt(0x0a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post := t.json.Post[subtest.Fork][subtest.Index]
|
||||||
|
msg, err := t.json.Tx.toMessage(post, baseFee)
|
||||||
|
if err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to recover tx with current signer
|
||||||
|
if len(post.TxBytes) != 0 {
|
||||||
|
var ttx types.Transaction
|
||||||
|
err := ttx.UnmarshalBinary(post.TxBytes)
|
||||||
|
if err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := types.Sender(types.LatestSigner(config), &ttx); err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the EVM.
|
||||||
|
txContext := core.NewEVMTxContext(msg)
|
||||||
|
context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
|
||||||
|
context.GetHash = vmTestBlockHash
|
||||||
|
context.BaseFee = baseFee
|
||||||
|
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
|
||||||
|
|
||||||
|
// Create "contract" for sender to cache code analysis.
|
||||||
|
sender := vm.NewContract(vm.AccountRef(msg.From()), vm.AccountRef(msg.From()),
|
||||||
|
nil, 0)
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
// Execute the message.
|
||||||
|
snapshot := statedb.Snapshot()
|
||||||
|
_, _, err = evm.Call(sender, *msg.To(), msg.Data(), msg.Gas(), msg.Value())
|
||||||
|
if err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
statedb.RevertToSnapshot(snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue