Skip to content

Commit

Permalink
refactor: replace NewOperation with OperationBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
ARR4N committed Sep 18, 2024
1 parent 55ef2a4 commit 6a5de75
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 22 deletions.
49 changes: 35 additions & 14 deletions core/vm/jump_table.libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,42 @@ func overrideJumpTable(r params.Rules, jt *JumpTable) *JumpTable {
return libevmHooks.OverrideJumpTable(r, jt)
}

// NewOperation constructs a new operation for inclusion in a [JumpTable].
func NewOperation(
execute func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error),
constantGas uint64,
dynamicGas func(e *EVM, c *Contract, s *Stack, m *Memory, u uint64) (uint64, error),
minStack, maxStack int,
memorySize func(s *Stack) (size uint64, overflow bool),
) *operation {
return &operation{
execute,
constantGas,
dynamicGas,
minStack, maxStack,
memorySize,
// An OperationBuilder is a factory for a new operations to include in a
// [JumpTable]. All of its fields are required.
type OperationBuilder[G interface {
uint64 | func(_ *EVM, _ *Contract, _ *Stack, _ *Memory, requestedMemorySize uint64) (uint64, error)
}] struct {
Execute func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
Gas G
MinStack, MaxStack int
MemorySize func(s *Stack) (size uint64, overflow bool)
}

type (
// OperationBuilderConstantGas is the constant-gas version of an
// OperationBuilder.
OperationBuilderConstantGas = OperationBuilder[uint64]
// OperationBuilderDynamicGas is the dynamic-gas version of an
// OperationBuilder.
OperationBuilderDynamicGas = OperationBuilder[func(_ *EVM, _ *Contract, _ *Stack, _ *Memory, requestedMemorySize uint64) (uint64, error)]
)

// Build constructs the operation.
func (b OperationBuilder[G]) Build() *operation {
o := &operation{
execute: b.Execute,
minStack: b.MinStack,
maxStack: b.MaxStack,
memorySize: b.MemorySize,
}

switch g := any(b.Gas).(type) {
case uint64:
o.constantGas = g
case gasFunc:
o.dynamicGas = g
}
return o
}

// Hooks are arbitrary configuration functions to modify default VM behaviour.
Expand Down
22 changes: 14 additions & 8 deletions core/vm/jump_table.libevm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package vm_test
import (
"fmt"
"math/big"
"reflect"
"testing"

"github.com/holiman/uint256"
Expand Down Expand Up @@ -53,24 +54,22 @@ func TestOverrideJumpTable(t *testing.T) {

vmHooks := &vmHooksStub{
replacement: &vm.JumpTable{
opcode: vm.NewOperation(
func(pc *uint64, interpreter *vm.EVMInterpreter, callContext *vm.ScopeContext) ([]byte, error) {
opcode: vm.OperationBuilderConstantGas{
Execute: func(pc *uint64, interpreter *vm.EVMInterpreter, callContext *vm.ScopeContext) ([]byte, error) {
executed = true
return nil, nil
},
gasCost, nil,
0, 0,
func(s *vm.Stack) (size uint64, overflow bool) {
Gas: gasCost,
MemorySize: func(s *vm.Stack) (size uint64, overflow bool) {
return 0, false
},
),
}.Build(),
},
}
vm.RegisterHooks(vmHooks)

t.Run("LookupInstructionSet", func(t *testing.T) {
_, evm := ethtest.NewZeroEVM(t)
rules := evm.ChainConfig().Rules(big.NewInt(0), false, 0)
rules := new(params.ChainConfig).Rules(big.NewInt(0), false, 0)

for _, b := range []bool{false, true} {
vmHooks.overridden = false
Expand Down Expand Up @@ -99,3 +98,10 @@ func TestOverrideJumpTable(t *testing.T) {
assert.Equal(t, gasLimit-gasCost, gasRemaining, "gas remaining")
})
}

func TestOperationFieldCount(t *testing.T) {
// The libevm OperationBuilder assumes that the 6 struct fields are the only
// ones.
op := vm.OperationBuilderConstantGas{}.Build()
require.Equalf(t, 6, reflect.TypeOf(*op).NumField(), "number of fields in %T struct", *op)
}

0 comments on commit 6a5de75

Please sign in to comment.