Skip to content

Commit

Permalink
Merge pull request #119 from blocknative/TS_nbc
Browse files Browse the repository at this point in the history
More decoding benchmarks
  • Loading branch information
tyler-smith authored Sep 21, 2023
2 parents 2b8dc12 + bfc267e commit 70c76f7
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 20 deletions.
81 changes: 81 additions & 0 deletions eth/tracers/blocknative/decoder/calldata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/hex"
"encoding/json"
"math/big"
"os"
"path/filepath"
"testing"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -37,6 +39,85 @@ func BenchmarkDecodeCalldata(B *testing.B) {
executeTests(B, tests[i%len(tests)])
}
}
func BenchmarkDecodeCalldataWithStandardVectors(b *testing.B) {
testVectors, err := loadTestVectors()
require.NoError(b, err)

calls := []*testCall{}
var addAllCalls func(calls []*testVector)
addAllCalls = func(tests []*testVector) {
for _, test := range tests {
input, err := hex.DecodeString(test.Input[2:])
require.NoError(b, err)
value, _ := new(big.Int).SetString(test.Value, 10)
contract := &Contract{Type: contractTypesByName[test.Type]}
calls = append(calls, &testCall{
contract: contract,
from: common.HexToAddress(test.From),
to: common.HexToAddress(test.To),
value: NewAmount(value),
input: input,
})
addAllCalls(test.Calls)
}
}
for _, v := range testVectors {
addAllCalls(v.Calls)
}

// Run the benchmark, decoding each call in turn.
var call testCall
for i := 0; i < b.N; i++ {
call = *calls[i%len(calls)]
_, _ = decodeCallData(call.from, call.contract, call.input)
}
}

type testVector struct {
Type string `json:"type"`
From string `json:"from"`
To string `json:"to,omitempty"`
Value string `json:"value,omitempty"`
Input string `json:"input"`
Calls []*testVector `json:"calls,omitempty"`
}

type testCall struct {
contract *Contract
from common.Address
to common.Address
value *Amount
input []byte
}

func loadTestVectors() ([]*testVector, error) {
testVectorDirs := []string{
"../../internal/tracetest/testdata/txnOpCode_tracer",
"../../internal/tracetest/testdata/txnOpCode_tracer_with_netbalchanges",
}

var testVectors []*testVector
for _, dirPath := range testVectorDirs {
files, err := os.ReadDir(dirPath)
if err != nil {
return nil, err
}

for _, file := range files {
test := new(struct {
Result *testVector `json:"result"`
})
if blob, err := os.ReadFile(filepath.Join(dirPath, file.Name())); err != nil {
return nil, err
} else if err := json.Unmarshal(blob, test); err != nil {
return nil, err
}

testVectors = append(testVectors, test.Result.Calls...)
}
}
return testVectors, nil
}

func getTestCases() []decodeCallDataTest {
return []decodeCallDataTest{
Expand Down
26 changes: 26 additions & 0 deletions eth/tracers/blocknative/decoder_evm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package blocknative

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"math"
)

// decoderEVM contains the functionality required by the decoder from the EVM.
type decoderEVM struct {
*vm.EVM
}

// GetCode returns the bytecode of the account with the given address, or nil
// if the account is not a contract.
func (d decoderEVM) GetCode(addr common.Address) []byte {
return d.StateDB.GetCode(addr)
}

// CallCode executes the given method on the code at the given address.
func (d decoderEVM) CallCode(addr common.Address, method []byte) ([]byte, error) {
code := d.StateDB.GetCode(addr)
contract := vm.NewContract(vm.AccountRef(common.Address{}), vm.AccountRef(addr), common.Big0, math.MaxUint64)
contract.SetCallCode(&addr, d.StateDB.GetCodeHash(addr), code)
return d.Interpreter().Run(contract, method, false)
}
20 changes: 0 additions & 20 deletions eth/tracers/blocknative/txnOpCodeTracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package blocknative
import (
"encoding/json"
"fmt"
"math"
"math/big"
"sync/atomic"
"time"
Expand Down Expand Up @@ -261,22 +260,3 @@ func finalizeCallFrame(call *CallFrame, output []byte, gasUsed uint64, err error
// The call was successful so decode the output.
call.Output = bytesToHex(output)
}

type decoderEVM struct {
*vm.EVM
}

func (d decoderEVM) GetCode(addr common.Address) []byte {
return d.StateDB.GetCode(addr)
}

func (d decoderEVM) CallCode(addr common.Address, method []byte) ([]byte, error) {
code := d.StateDB.GetCode(addr)
contract := vm.NewContract(vm.AccountRef(common.Address{}), vm.AccountRef(addr), common.Big0, math.MaxUint64)
contract.SetCallCode(&addr, d.StateDB.GetCodeHash(addr), code)
ret, err := d.Interpreter().Run(contract, method, false)
if err != nil {
return nil, err
}
return ret, nil
}

0 comments on commit 70c76f7

Please sign in to comment.