Skip to content

Commit ce10b13

Browse files
committed
test: improved strategy and coverage
1 parent 482edd9 commit ce10b13

File tree

5 files changed

+70
-20
lines changed

5 files changed

+70
-20
lines changed

core/vm/interpreter.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,8 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
9494
extraEips = append(extraEips, eip)
9595
}
9696
}
97-
if evm.chainRules.Hooks().OverrideJumpTable() {
98-
table = libevmHooks.OverrideJumpTable(evm.chainRules, table)
99-
}
10097
evm.Config.ExtraEips = extraEips
98+
table = overrideJumpTable(evm.chainRules, table)
10199
return &EVMInterpreter{evm: evm, table: table}
102100
}
103101

core/vm/jump_table.libevm.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@ package vm
22

33
import "github.com/ethereum/go-ethereum/params"
44

5+
// overrideJumpTable returns `libevmHooks.OverrideJumpTable(r,jt)“ i.f.f. the
6+
// Rules' hooks indicate that it must, otherwise it echoes `jt` unchanged.
7+
func overrideJumpTable(r params.Rules, jt *JumpTable) *JumpTable {
8+
if !r.Hooks().OverrideJumpTable() {
9+
return jt
10+
}
11+
// We don't check that libevmHooks is non-nil because the user has clearly
12+
// signified that they want an override. A nil-pointer dereference will
13+
// occur in tests whereas graceful degradation would frustrate the user with
14+
// a hard-to-find bug.
15+
return libevmHooks.OverrideJumpTable(r, jt)
16+
}
17+
518
// NewOperation constructs a new operation for inclusion in a [JumpTable].
619
func NewOperation(
720
execute func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error),

core/vm/jump_table.libevm_test.go

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package vm_test
22

33
import (
44
"fmt"
5+
"math/big"
56
"testing"
67

78
"github.com/ethereum/go-ethereum/core/vm"
@@ -15,9 +16,14 @@ import (
1516

1617
type vmHooksStub struct {
1718
replacement *vm.JumpTable
19+
overridden bool
1820
}
1921

22+
var _ vm.Hooks = (*vmHooksStub)(nil)
23+
24+
// OverrideJumpTable overrides all non-nil operations from s.replacement .
2025
func (s *vmHooksStub) OverrideJumpTable(_ params.Rules, jt *vm.JumpTable) *vm.JumpTable {
26+
s.overridden = true
2127
for op, instr := range s.replacement {
2228
if instr != nil {
2329
fmt.Println(op, instr)
@@ -28,22 +34,30 @@ func (s *vmHooksStub) OverrideJumpTable(_ params.Rules, jt *vm.JumpTable) *vm.Ju
2834
}
2935

3036
func TestOverrideJumpTable(t *testing.T) {
37+
override := new(bool)
3138
hooks := &hookstest.Stub{
32-
OverrideJumpTableFlag: true,
39+
OverrideJumpTableFn: func() bool {
40+
return *override
41+
},
3342
}
3443
hooks.Register(t)
3544

36-
var called bool
37-
const opcode = 1
45+
const (
46+
opcode = 1
47+
gasLimit uint64 = 1e6
48+
)
49+
rng := ethtest.NewPseudoRand(142857)
50+
gasCost := 1 + rng.Uint64n(gasLimit)
51+
executed := false
3852

3953
vmHooks := &vmHooksStub{
4054
replacement: &vm.JumpTable{
4155
opcode: vm.NewOperation(
4256
func(pc *uint64, interpreter *vm.EVMInterpreter, callContext *vm.ScopeContext) ([]byte, error) {
43-
called = true
57+
executed = true
4458
return nil, nil
4559
},
46-
10, nil,
60+
gasCost, nil,
4761
0, 0,
4862
func(s *vm.Stack) (size uint64, overflow bool) {
4963
return 0, false
@@ -53,14 +67,34 @@ func TestOverrideJumpTable(t *testing.T) {
5367
}
5468
vm.RegisterHooks(vmHooks)
5569

56-
state, evm := ethtest.NewZeroEVM(t)
70+
t.Run("LookupInstructionSet", func(t *testing.T) {
71+
_, evm := ethtest.NewZeroEVM(t)
72+
rules := evm.ChainConfig().Rules(big.NewInt(0), false, 0)
5773

58-
rng := ethtest.NewPseudoRand(142857)
59-
contract := rng.Address()
60-
state.CreateAccount(contract)
61-
state.SetCode(contract, []byte{opcode})
74+
for _, b := range []bool{false, true} {
75+
vmHooks.overridden = false
76+
77+
*override = b
78+
_, err := vm.LookupInstructionSet(rules)
79+
require.NoError(t, err)
80+
require.Equal(t, b, vmHooks.overridden, "vm.Hooks.OverrideJumpTable() called i.f.f. params.RulesHooks.OverrideJumpTable() returns true")
81+
}
82+
})
83+
84+
t.Run("EVMInterpreter", func(t *testing.T) {
85+
// We don't need to test the non-override case in EVMInterpreter because
86+
// that uses code shared with LookupInstructionSet. Here we only care
87+
// that the op gets executed as expected.
88+
*override = true
89+
state, evm := ethtest.NewZeroEVM(t)
90+
91+
contract := rng.Address()
92+
state.CreateAccount(contract)
93+
state.SetCode(contract, []byte{opcode})
6294

63-
_, _, err := evm.Call(vm.AccountRef(rng.Address()), contract, []byte{}, 1e6, uint256.NewInt(0))
64-
require.NoError(t, err)
65-
assert.True(t, called)
95+
_, gasRemaining, err := evm.Call(vm.AccountRef(rng.Address()), contract, []byte{}, gasLimit, uint256.NewInt(0))
96+
require.NoError(t, err, "evm.Call([contract with overridden opcode])")
97+
assert.True(t, executed, "executionFunc was called")
98+
assert.Equal(t, gasLimit-gasCost, gasRemaining, "gas remaining")
99+
})
66100
}

core/vm/jump_table_export.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import (
2626
// the rules.
2727
func LookupInstructionSet(rules params.Rules) (jt JumpTable, err error) {
2828
defer func() {
29-
if err == nil && rules.Hooks().OverrideJumpTable() {
30-
jt = *libevmHooks.OverrideJumpTable(rules, &jt)
29+
if err == nil { // NOTE `err ==` NOT !=
30+
jt = *overrideJumpTable(rules, &jt)
3131
}
3232
}()
3333
switch {

libevm/hookstest/stub.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type Stub struct {
2828
PrecompileOverrides map[common.Address]libevm.PrecompiledContract
2929
CanExecuteTransactionFn func(common.Address, *common.Address, libevm.StateReader) error
3030
CanCreateContractFn func(*libevm.AddressContext, uint64, libevm.StateReader) (uint64, error)
31-
OverrideJumpTableFlag bool
31+
OverrideJumpTableFn func() bool
3232
}
3333

3434
// Register is a convenience wrapper for registering s as both the
@@ -71,8 +71,13 @@ func (s Stub) CanCreateContract(cc *libevm.AddressContext, gas uint64, sr libevm
7171
return gas, nil
7272
}
7373

74+
// OverrideJumpTable proxies arguments to the s.OverrideJumpTableFn function if
75+
// non-nil, otherwise it acts as a noop.
7476
func (s Stub) OverrideJumpTable() bool {
75-
return s.OverrideJumpTableFlag
77+
if f := s.OverrideJumpTableFn; f != nil {
78+
return f()
79+
}
80+
return false
7681
}
7782

7883
var _ interface {

0 commit comments

Comments
 (0)