Skip to content

Commit 94fe5c6

Browse files
committed
core/vm: generic not-traced EVM implementation
this allows the EVM to follow the not-traced codepaths when it is not configured for tracing and skip the runtime checks
1 parent c3ef6c7 commit 94fe5c6

14 files changed

+260
-238
lines changed

core/vm/contract.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package vm
1818

1919
import (
2020
"github.com/ethereum/go-ethereum/common"
21-
"github.com/ethereum/go-ethereum/core/tracing"
2221
"github.com/holiman/uint256"
2322
)
2423

@@ -125,29 +124,6 @@ func (c *Contract) Caller() common.Address {
125124
return c.caller
126125
}
127126

128-
// UseGas attempts the use gas and subtracts it and returns true on success
129-
func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) {
130-
if c.Gas < gas {
131-
return false
132-
}
133-
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
134-
logger.OnGasChange(c.Gas, c.Gas-gas, reason)
135-
}
136-
c.Gas -= gas
137-
return true
138-
}
139-
140-
// RefundGas refunds gas to the contract
141-
func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
142-
if gas == 0 {
143-
return
144-
}
145-
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
146-
logger.OnGasChange(c.Gas, c.Gas+gas, reason)
147-
}
148-
c.Gas += gas
149-
}
150-
151127
// Address returns the contracts address
152128
func (c *Contract) Address() common.Address {
153129
return c.address

core/vm/contracts.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,12 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
257257
// - the returned bytes,
258258
// - the _remaining_ gas,
259259
// - any error that occurred
260-
func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
260+
func RunPrecompiledContract[TS TracingSwitch](p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
261261
gasCost := p.RequiredGas(input)
262262
if suppliedGas < gasCost {
263263
return nil, 0, ErrOutOfGas
264264
}
265-
if logger != nil && logger.OnGasChange != nil {
265+
if tracingIsEnabled[TS]() && logger.OnGasChange != nil {
266266
logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
267267
}
268268
suppliedGas -= gasCost

core/vm/contracts_fuzz_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func FuzzPrecompiledContracts(f *testing.F) {
3636
return
3737
}
3838
inWant := string(input)
39-
RunPrecompiledContract(p, input, gas, nil)
39+
RunPrecompiledContract[TracingDisabled](p, input, gas, nil)
4040
if inHave := string(input); inWant != inHave {
4141
t.Errorf("Precompiled %v modified input data", a)
4242
}

core/vm/contracts_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
9999
in := common.Hex2Bytes(test.Input)
100100
gas := p.RequiredGas(in)
101101
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
102-
if res, _, err := RunPrecompiledContract(p, in, gas, nil); err != nil {
102+
if res, _, err := RunPrecompiledContract[TracingDisabled](p, in, gas, nil); err != nil {
103103
t.Error(err)
104104
} else if common.Bytes2Hex(res) != test.Expected {
105105
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
@@ -121,7 +121,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
121121
gas := p.RequiredGas(in) - 1
122122

123123
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
124-
_, _, err := RunPrecompiledContract(p, in, gas, nil)
124+
_, _, err := RunPrecompiledContract[TracingDisabled](p, in, gas, nil)
125125
if err.Error() != "out of gas" {
126126
t.Errorf("Expected error [out of gas], got [%v]", err)
127127
}
@@ -138,7 +138,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing
138138
in := common.Hex2Bytes(test.Input)
139139
gas := p.RequiredGas(in)
140140
t.Run(test.Name, func(t *testing.T) {
141-
_, _, err := RunPrecompiledContract(p, in, gas, nil)
141+
_, _, err := RunPrecompiledContract[TracingDisabled](p, in, gas, nil)
142142
if err.Error() != test.ExpectedError {
143143
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
144144
}
@@ -170,7 +170,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
170170
bench.ResetTimer()
171171
for i := 0; i < bench.N; i++ {
172172
copy(data, in)
173-
res, _, err = RunPrecompiledContract(p, data, reqGas, nil)
173+
res, _, err = RunPrecompiledContract[TracingDisabled](p, data, reqGas, nil)
174174
}
175175
bench.StopTimer()
176176
elapsed := uint64(time.Since(start))

core/vm/eips.go

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,36 @@ import (
2727
"github.com/holiman/uint256"
2828
)
2929

30-
var activators = map[int]func(*JumpTable){
31-
5656: enable5656,
32-
6780: enable6780,
33-
3855: enable3855,
34-
3860: enable3860,
35-
3529: enable3529,
36-
3198: enable3198,
37-
2929: enable2929,
38-
2200: enable2200,
39-
1884: enable1884,
40-
1344: enable1344,
41-
1153: enable1153,
42-
4762: enable4762,
43-
7702: enable7702,
44-
7939: enable7939,
30+
var activators = map[int][2]func(*JumpTable){
31+
5656: {enable5656},
32+
6780: {enable6780},
33+
3855: {enable3855},
34+
3860: {enable3860},
35+
3529: {enable3529},
36+
3198: {enable3198},
37+
2929: {enable2929[TracingEnabled], enable2929[TracingDisabled]},
38+
2200: {enable2200},
39+
1884: {enable1884},
40+
1344: {enable1344},
41+
1153: {enable1153},
42+
4762: {enable4762[TracingEnabled], enable4762[TracingDisabled]},
43+
7702: {enable7702[TracingEnabled], enable7702[TracingDisabled]},
44+
7939: {enable7939},
4545
}
4646

4747
// EnableEIP enables the given EIP on the config.
4848
// This operation writes in-place, and callers need to ensure that the globally
4949
// defined jump tables are not polluted.
50-
func EnableEIP(eipNum int, jt *JumpTable) error {
51-
enablerFn, ok := activators[eipNum]
50+
func EnableEIP(eipNum int, jt *JumpTable, traced bool) error {
51+
enablerFns, ok := activators[eipNum]
5252
if !ok {
5353
return fmt.Errorf("undefined eip %d", eipNum)
5454
}
55-
enablerFn(jt)
55+
if traced || enablerFns[1] == nil {
56+
enablerFns[0](jt)
57+
} else {
58+
enablerFns[1](jt)
59+
}
5660
return nil
5761
}
5862

@@ -122,7 +126,7 @@ func enable2200(jt *JumpTable) {
122126

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

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

143147
jt[CALL].constantGas = params.WarmStorageReadCostEIP2929
144-
jt[CALL].dynamicGas = gasCallEIP2929
148+
jt[CALL].dynamicGas = makeCallVariantGasCallEIP2929[TS](gasCall, 1)
145149

146150
jt[CALLCODE].constantGas = params.WarmStorageReadCostEIP2929
147-
jt[CALLCODE].dynamicGas = gasCallCodeEIP2929
151+
jt[CALLCODE].dynamicGas = makeCallVariantGasCallEIP2929[TS](gasCallCode, 1)
148152

149153
jt[STATICCALL].constantGas = params.WarmStorageReadCostEIP2929
150-
jt[STATICCALL].dynamicGas = gasStaticCallEIP2929
154+
jt[STATICCALL].dynamicGas = makeCallVariantGasCallEIP2929[TS](gasStaticCall, 1)
151155

152156
jt[DELEGATECALL].constantGas = params.WarmStorageReadCostEIP2929
153-
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP2929
157+
jt[DELEGATECALL].dynamicGas = makeCallVariantGasCallEIP2929[TS](gasDelegateCall, 1)
154158

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

345-
func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
349+
func opExtCodeCopyEIP4762[TS TracingSwitch](pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
346350
var (
347351
stack = scope.Stack
348352
a = stack.pop()
@@ -358,7 +362,7 @@ func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, er
358362
code := evm.StateDB.GetCode(addr)
359363
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
360364
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas)
361-
scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
365+
useGas[TS](scope.Contract, consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
362366
if consumed < wanted {
363367
return nil, ErrOutOfGas
364368
}
@@ -370,7 +374,7 @@ func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, er
370374
// opPush1EIP4762 handles the special case of PUSH1 opcode for EIP-4762, which
371375
// need not worry about the adjusted bound logic when adding the PUSHDATA to
372376
// the list of access events.
373-
func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
377+
func opPush1EIP4762[TS TracingSwitch](pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
374378
var (
375379
codeLen = uint64(len(scope.Contract.Code))
376380
integer = new(uint256.Int)
@@ -384,7 +388,7 @@ func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
384388
// advanced past this boundary.
385389
contractAddr := scope.Contract.Address()
386390
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
387-
scope.Contract.UseGas(wanted, evm.Config.Tracer, tracing.GasChangeUnspecified)
391+
useGas[TS](scope.Contract, wanted, evm.Config.Tracer, tracing.GasChangeUnspecified)
388392
if consumed < wanted {
389393
return nil, ErrOutOfGas
390394
}
@@ -395,7 +399,7 @@ func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
395399
return nil, nil
396400
}
397401

398-
func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
402+
func makePushEIP4762[TS TracingSwitch](size uint64, pushByteSize int) executionFunc {
399403
return func(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
400404
var (
401405
codeLen = len(scope.Contract.Code)
@@ -412,7 +416,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
412416
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall {
413417
contractAddr := scope.Contract.Address()
414418
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
415-
scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
419+
useGas[TS](scope.Contract, consumed, evm.Config.Tracer, tracing.GasChangeUnspecified)
416420
if consumed < wanted {
417421
return nil, ErrOutOfGas
418422
}
@@ -423,7 +427,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
423427
}
424428
}
425429

426-
func enable4762(jt *JumpTable) {
430+
func enable4762[TS TracingSwitch](jt *JumpTable) {
427431
jt[SSTORE] = &operation{
428432
dynamicGas: gasSStore4762,
429433
execute: opSstore,
@@ -459,7 +463,7 @@ func enable4762(jt *JumpTable) {
459463
}
460464

461465
jt[EXTCODECOPY] = &operation{
462-
execute: opExtCodeCopyEIP4762,
466+
execute: opExtCodeCopyEIP4762[TS],
463467
dynamicGas: gasExtCodeCopyEIP4762,
464468
minStack: minStack(4, 0),
465469
maxStack: maxStack(4, 0),
@@ -484,7 +488,7 @@ func enable4762(jt *JumpTable) {
484488
}
485489

486490
jt[CREATE] = &operation{
487-
execute: opCreate,
491+
execute: opCreate[TS],
488492
constantGas: params.CreateNGasEip4762,
489493
dynamicGas: gasCreateEip3860,
490494
minStack: minStack(3, 1),
@@ -493,7 +497,7 @@ func enable4762(jt *JumpTable) {
493497
}
494498

495499
jt[CREATE2] = &operation{
496-
execute: opCreate2,
500+
execute: opCreate2[TS],
497501
constantGas: params.CreateNGasEip4762,
498502
dynamicGas: gasCreate2Eip3860,
499503
minStack: minStack(4, 1),
@@ -502,46 +506,46 @@ func enable4762(jt *JumpTable) {
502506
}
503507

504508
jt[CALL] = &operation{
505-
execute: opCall,
509+
execute: opCall[TS],
506510
dynamicGas: gasCallEIP4762,
507511
minStack: minStack(7, 1),
508512
maxStack: maxStack(7, 1),
509513
memorySize: memoryCall,
510514
}
511515

512516
jt[CALLCODE] = &operation{
513-
execute: opCallCode,
517+
execute: opCallCode[TS],
514518
dynamicGas: gasCallCodeEIP4762,
515519
minStack: minStack(7, 1),
516520
maxStack: maxStack(7, 1),
517521
memorySize: memoryCall,
518522
}
519523

520524
jt[STATICCALL] = &operation{
521-
execute: opStaticCall,
525+
execute: opStaticCall[TS],
522526
dynamicGas: gasStaticCallEIP4762,
523527
minStack: minStack(6, 1),
524528
maxStack: maxStack(6, 1),
525529
memorySize: memoryStaticCall,
526530
}
527531

528532
jt[DELEGATECALL] = &operation{
529-
execute: opDelegateCall,
533+
execute: opDelegateCall[TS],
530534
dynamicGas: gasDelegateCallEIP4762,
531535
minStack: minStack(6, 1),
532536
maxStack: maxStack(6, 1),
533537
memorySize: memoryDelegateCall,
534538
}
535539

536540
jt[PUSH1] = &operation{
537-
execute: opPush1EIP4762,
541+
execute: opPush1EIP4762[TS],
538542
constantGas: GasFastestStep,
539543
minStack: minStack(0, 1),
540544
maxStack: maxStack(0, 1),
541545
}
542546
for i := 1; i < 32; i++ {
543547
jt[PUSH1+OpCode(i)] = &operation{
544-
execute: makePushEIP4762(uint64(i+1), i+1),
548+
execute: makePushEIP4762[TS](uint64(i+1), i+1),
545549
constantGas: GasFastestStep,
546550
minStack: minStack(0, 1),
547551
maxStack: maxStack(0, 1),
@@ -550,9 +554,9 @@ func enable4762(jt *JumpTable) {
550554
}
551555

552556
// enable7702 the EIP-7702 changes to support delegation designators.
553-
func enable7702(jt *JumpTable) {
554-
jt[CALL].dynamicGas = gasCallEIP7702
555-
jt[CALLCODE].dynamicGas = gasCallCodeEIP7702
556-
jt[STATICCALL].dynamicGas = gasStaticCallEIP7702
557-
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702
557+
func enable7702[TS TracingSwitch](jt *JumpTable) {
558+
jt[CALL].dynamicGas = makeCallVariantGasCallEIP7702[TS](gasCall)
559+
jt[CALLCODE].dynamicGas = makeCallVariantGasCallEIP7702[TS](gasCallCode)
560+
jt[STATICCALL].dynamicGas = makeCallVariantGasCallEIP7702[TS](gasStaticCall)
561+
jt[DELEGATECALL].dynamicGas = makeCallVariantGasCallEIP7702[TS](gasDelegateCall)
558562
}

0 commit comments

Comments
 (0)