Skip to content

core/vm: generic not-traced EVM implementation #32409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 0 additions & 24 deletions core/vm/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package vm

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/holiman/uint256"
)

Expand Down Expand Up @@ -125,29 +124,6 @@ func (c *Contract) Caller() common.Address {
return c.caller
}

// UseGas attempts the use gas and subtracts it and returns true on success
func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) {
if c.Gas < gas {
return false
}
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
logger.OnGasChange(c.Gas, c.Gas-gas, reason)
}
c.Gas -= gas
return true
}

// RefundGas refunds gas to the contract
func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
if gas == 0 {
return
}
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
logger.OnGasChange(c.Gas, c.Gas+gas, reason)
}
c.Gas += gas
}

// Address returns the contracts address
func (c *Contract) Address() common.Address {
return c.address
Expand Down
4 changes: 2 additions & 2 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,12 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
// - the returned bytes,
// - the _remaining_ gas,
// - any error that occurred
func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
func RunPrecompiledContract[TS TracingSwitch](p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
gasCost := p.RequiredGas(input)
if suppliedGas < gasCost {
return nil, 0, ErrOutOfGas
}
if logger != nil && logger.OnGasChange != nil {
if tracingIsEnabled[TS]() && logger.OnGasChange != nil {
logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
}
suppliedGas -= gasCost
Expand Down
2 changes: 1 addition & 1 deletion core/vm/contracts_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func FuzzPrecompiledContracts(f *testing.F) {
return
}
inWant := string(input)
RunPrecompiledContract(p, input, gas, nil)
RunPrecompiledContract[TracingDisabled](p, input, gas, nil)
if inHave := string(input); inWant != inHave {
t.Errorf("Precompiled %v modified input data", a)
}
Expand Down
8 changes: 4 additions & 4 deletions core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
in := common.Hex2Bytes(test.Input)
gas := p.RequiredGas(in)
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
if res, _, err := RunPrecompiledContract(p, in, gas, nil); err != nil {
if res, _, err := RunPrecompiledContract[TracingDisabled](p, in, gas, nil); err != nil {
t.Error(err)
} else if common.Bytes2Hex(res) != test.Expected {
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
Expand All @@ -121,7 +121,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
gas := p.RequiredGas(in) - 1

t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
_, _, err := RunPrecompiledContract(p, in, gas, nil)
_, _, err := RunPrecompiledContract[TracingDisabled](p, in, gas, nil)
if err.Error() != "out of gas" {
t.Errorf("Expected error [out of gas], got [%v]", err)
}
Expand All @@ -138,7 +138,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing
in := common.Hex2Bytes(test.Input)
gas := p.RequiredGas(in)
t.Run(test.Name, func(t *testing.T) {
_, _, err := RunPrecompiledContract(p, in, gas, nil)
_, _, err := RunPrecompiledContract[TracingDisabled](p, in, gas, nil)
if err.Error() != test.ExpectedError {
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
}
Expand Down Expand Up @@ -170,7 +170,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
copy(data, in)
res, _, err = RunPrecompiledContract(p, data, reqGas, nil)
res, _, err = RunPrecompiledContract[TracingDisabled](p, data, reqGas, nil)
}
bench.StopTimer()
elapsed := uint64(time.Since(start))
Expand Down
92 changes: 48 additions & 44 deletions core/vm/eips.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,36 @@ import (
"github.com/holiman/uint256"
)

var activators = map[int]func(*JumpTable){
5656: enable5656,
6780: enable6780,
3855: enable3855,
3860: enable3860,
3529: enable3529,
3198: enable3198,
2929: enable2929,
2200: enable2200,
1884: enable1884,
1344: enable1344,
1153: enable1153,
4762: enable4762,
7702: enable7702,
7939: enable7939,
var activators = map[int][2]func(*JumpTable){
5656: {enable5656},
6780: {enable6780},
3855: {enable3855},
3860: {enable3860},
3529: {enable3529},
3198: {enable3198},
2929: {enable2929[TracingEnabled], enable2929[TracingDisabled]},
2200: {enable2200},
1884: {enable1884},
1344: {enable1344},
1153: {enable1153},
4762: {enable4762[TracingEnabled], enable4762[TracingDisabled]},
7702: {enable7702[TracingEnabled], enable7702[TracingDisabled]},
7939: {enable7939},
}

// EnableEIP enables the given EIP on the config.
// This operation writes in-place, and callers need to ensure that the globally
// defined jump tables are not polluted.
func EnableEIP(eipNum int, jt *JumpTable) error {
enablerFn, ok := activators[eipNum]
func EnableEIP(eipNum int, jt *JumpTable, traced bool) error {
enablerFns, ok := activators[eipNum]
if !ok {
return fmt.Errorf("undefined eip %d", eipNum)
}
enablerFn(jt)
if traced || enablerFns[1] == nil {
enablerFns[0](jt)
} else {
enablerFns[1](jt)
}
return nil
}

Expand Down Expand Up @@ -122,7 +126,7 @@ func enable2200(jt *JumpTable) {

// enable2929 enables "EIP-2929: Gas cost increases for state access opcodes"
// https://eips.ethereum.org/EIPS/eip-2929
func enable2929(jt *JumpTable) {
func enable2929[TS TracingSwitch](jt *JumpTable) {
jt[SSTORE].dynamicGas = gasSStoreEIP2929

jt[SLOAD].constantGas = 0
Expand All @@ -141,16 +145,16 @@ func enable2929(jt *JumpTable) {
jt[BALANCE].dynamicGas = gasEip2929AccountCheck

jt[CALL].constantGas = params.WarmStorageReadCostEIP2929
jt[CALL].dynamicGas = gasCallEIP2929
jt[CALL].dynamicGas = makeCallVariantGasCallEIP2929[TS](gasCall, 1)

jt[CALLCODE].constantGas = params.WarmStorageReadCostEIP2929
jt[CALLCODE].dynamicGas = gasCallCodeEIP2929
jt[CALLCODE].dynamicGas = makeCallVariantGasCallEIP2929[TS](gasCallCode, 1)

jt[STATICCALL].constantGas = params.WarmStorageReadCostEIP2929
jt[STATICCALL].dynamicGas = gasStaticCallEIP2929
jt[STATICCALL].dynamicGas = makeCallVariantGasCallEIP2929[TS](gasStaticCall, 1)

jt[DELEGATECALL].constantGas = params.WarmStorageReadCostEIP2929
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP2929
jt[DELEGATECALL].dynamicGas = makeCallVariantGasCallEIP2929[TS](gasDelegateCall, 1)

// This was previously part of the dynamic cost, but we're using it as a constantGas
// factor here
Expand Down Expand Up @@ -342,7 +346,7 @@ func enable6780(jt *JumpTable) {
}
}

func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
func opExtCodeCopyEIP4762[TS TracingSwitch](pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
stack = scope.Stack
a = stack.pop()
Expand All @@ -358,7 +362,7 @@ func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, er
code := evm.StateDB.GetCode(addr)
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas)
scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
useGas[TS](scope.Contract, consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
if consumed < wanted {
return nil, ErrOutOfGas
}
Expand All @@ -370,7 +374,7 @@ func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, er
// opPush1EIP4762 handles the special case of PUSH1 opcode for EIP-4762, which
// need not worry about the adjusted bound logic when adding the PUSHDATA to
// the list of access events.
func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
func opPush1EIP4762[TS TracingSwitch](pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
codeLen = uint64(len(scope.Contract.Code))
integer = new(uint256.Int)
Expand All @@ -384,7 +388,7 @@ func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
// advanced past this boundary.
contractAddr := scope.Contract.Address()
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
scope.Contract.UseGas(wanted, evm.Config.Tracer, tracing.GasChangeUnspecified)
useGas[TS](scope.Contract, wanted, evm.Config.Tracer, tracing.GasChangeUnspecified)
if consumed < wanted {
return nil, ErrOutOfGas
}
Expand All @@ -395,7 +399,7 @@ func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
return nil, nil
}

func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
func makePushEIP4762[TS TracingSwitch](size uint64, pushByteSize int) executionFunc {
return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
var (
codeLen = len(scope.Contract.Code)
Expand All @@ -412,7 +416,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall {
contractAddr := scope.Contract.Address()
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
useGas[TS](scope.Contract, consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
if consumed < wanted {
return nil, ErrOutOfGas
}
Expand All @@ -423,7 +427,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
}
}

func enable4762(jt *JumpTable) {
func enable4762[TS TracingSwitch](jt *JumpTable) {
jt[SSTORE] = &operation{
dynamicGas: gasSStore4762,
execute: opSstore,
Expand Down Expand Up @@ -459,7 +463,7 @@ func enable4762(jt *JumpTable) {
}

jt[EXTCODECOPY] = &operation{
execute: opExtCodeCopyEIP4762,
execute: opExtCodeCopyEIP4762[TS],
dynamicGas: gasExtCodeCopyEIP4762,
minStack: minStack(4, 0),
maxStack: maxStack(4, 0),
Expand All @@ -484,7 +488,7 @@ func enable4762(jt *JumpTable) {
}

jt[CREATE] = &operation{
execute: opCreate,
execute: opCreate[TS],
constantGas: params.CreateNGasEip4762,
dynamicGas: gasCreateEip3860,
minStack: minStack(3, 1),
Expand All @@ -493,7 +497,7 @@ func enable4762(jt *JumpTable) {
}

jt[CREATE2] = &operation{
execute: opCreate2,
execute: opCreate2[TS],
constantGas: params.CreateNGasEip4762,
dynamicGas: gasCreate2Eip3860,
minStack: minStack(4, 1),
Expand All @@ -502,46 +506,46 @@ func enable4762(jt *JumpTable) {
}

jt[CALL] = &operation{
execute: opCall,
execute: opCall[TS],
dynamicGas: gasCallEIP4762,
minStack: minStack(7, 1),
maxStack: maxStack(7, 1),
memorySize: memoryCall,
}

jt[CALLCODE] = &operation{
execute: opCallCode,
execute: opCallCode[TS],
dynamicGas: gasCallCodeEIP4762,
minStack: minStack(7, 1),
maxStack: maxStack(7, 1),
memorySize: memoryCall,
}

jt[STATICCALL] = &operation{
execute: opStaticCall,
execute: opStaticCall[TS],
dynamicGas: gasStaticCallEIP4762,
minStack: minStack(6, 1),
maxStack: maxStack(6, 1),
memorySize: memoryStaticCall,
}

jt[DELEGATECALL] = &operation{
execute: opDelegateCall,
execute: opDelegateCall[TS],
dynamicGas: gasDelegateCallEIP4762,
minStack: minStack(6, 1),
maxStack: maxStack(6, 1),
memorySize: memoryDelegateCall,
}

jt[PUSH1] = &operation{
execute: opPush1EIP4762,
execute: opPush1EIP4762[TS],
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
}
for i := 1; i < 32; i++ {
jt[PUSH1+OpCode(i)] = &operation{
execute: makePushEIP4762(uint64(i+1), i+1),
execute: makePushEIP4762[TS](uint64(i+1), i+1),
constantGas: GasFastestStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
Expand All @@ -550,9 +554,9 @@ func enable4762(jt *JumpTable) {
}

// enable7702 the EIP-7702 changes to support delegation designators.
func enable7702(jt *JumpTable) {
jt[CALL].dynamicGas = gasCallEIP7702
jt[CALLCODE].dynamicGas = gasCallCodeEIP7702
jt[STATICCALL].dynamicGas = gasStaticCallEIP7702
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702
func enable7702[TS TracingSwitch](jt *JumpTable) {
jt[CALL].dynamicGas = makeCallVariantGasCallEIP7702[TS](gasCall)
jt[CALLCODE].dynamicGas = makeCallVariantGasCallEIP7702[TS](gasCallCode)
jt[STATICCALL].dynamicGas = makeCallVariantGasCallEIP7702[TS](gasStaticCall)
jt[DELEGATECALL].dynamicGas = makeCallVariantGasCallEIP7702[TS](gasDelegateCall)
}
Loading