From 970caebba886e3239897555e932cff739b763707 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Fri, 11 Jul 2025 15:44:06 +0200 Subject: [PATCH 1/8] Instrument `gasCall` with multi gas --- core/vm/gas_table.go | 35 ++++--- core/vm/operaions_gas_test.go | 191 ++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 13 deletions(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 22a3d71c3..d3b208407 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -52,7 +52,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (*multigas.MultiGas, uint64, fee := newTotalFee - mem.lastGasCost mem.lastGasCost = newTotalFee - return multigas.ZeroGas(), fee, nil + return multigas.ComputationGas(fee), fee, nil } return multigas.ZeroGas(), 0, nil } @@ -404,46 +404,55 @@ func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (*multigas.MultiGas, uint64, error) { var ( - gas uint64 + multiGas = multigas.ZeroGas() transfersValue = !stack.Back(2).IsZero() address = common.Address(stack.Back(1).Bytes20()) ) + if evm.chainRules.IsEIP158 { if transfersValue && evm.StateDB.Empty(address) { - gas += params.CallNewAccountGas + multiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) } } else if !evm.StateDB.Exist(address) { - gas += params.CallNewAccountGas + multiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) } + if transfersValue && !evm.chainRules.IsEIP4762 { - gas += params.CallValueTransferGas + multiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallValueTransferGas) } - multiGas, memoryGas, err := memoryGasCost(mem, memorySize) + + memoryMultiGas, _, err := memoryGasCost(mem, memorySize) if err != nil { return multigas.ZeroGas(), 0, err } - // TODO(NIT-3484): Update multi dimensional gas here - var overflow bool - if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { + multiGas, overflow := multiGas.SafeAdd(multiGas, memoryMultiGas) + if overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } + if evm.chainRules.IsEIP4762 && !contract.IsSystemCall { if transfersValue { - gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address)) + valueTransferGas := evm.AccessEvents.ValueTransferGas(contract.Address(), address) + overflow := multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas) if overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } } } - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + + // NOTE(NIT-3483): Should callGas take into account all gas or only the computation gas? + computationGas := multiGas.Get(multigas.ResourceKindComputation) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, computationGas, stack.Back(0)) if err != nil { return multigas.ZeroGas(), 0, err } - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + overflow = multiGas.SafeIncrement(multigas.ResourceKindComputation, evm.callGasTemp) + if overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - return multiGas, gas, nil + singleGas, _ := multiGas.SingleGas() + return multiGas, singleGas, nil } func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (*multigas.MultiGas, uint64, error) { diff --git a/core/vm/operaions_gas_test.go b/core/vm/operaions_gas_test.go index 8a80dd4b1..e068eef1d 100644 --- a/core/vm/operaions_gas_test.go +++ b/core/vm/operaions_gas_test.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/arbitrum/multigas" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -449,3 +450,193 @@ func TestGasSStore4762(t *testing.T) { t.Errorf("Expected single gas %d, got %d", expectedSingleGas, singleGas) } } + +// CALL gas function test +func TestGasCall(t *testing.T) { + testCases := []struct { + name string + transfersValue bool + valueTransferGas uint64 + targetExists bool + targetEmpty bool + isEIP158 bool + isEIP4762 bool + isSystemCall bool + memorySize uint64 + }{ + { + name: "No value transfer, no memory expansion", + transfersValue: false, + valueTransferGas: 80000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + memorySize: 500, + }, + { + name: "Value transfer to existing account", + transfersValue: true, + valueTransferGas: 70000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + memorySize: 0, + }, + { + name: "Value transfer to empty account (EIP158)", + transfersValue: true, + valueTransferGas: 60000, + targetExists: true, + targetEmpty: true, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + memorySize: 0, + }, + { + name: "Non-existent account (pre-EIP158)", + transfersValue: false, + valueTransferGas: 55000, + targetExists: false, + targetEmpty: false, + isEIP158: false, + isEIP4762: false, + isSystemCall: false, + memorySize: 0, + }, + { + name: "EIP4762 value transfer (not system call)", + transfersValue: true, + valueTransferGas: 45000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + isSystemCall: false, + memorySize: 0, + }, + { + name: "EIP4762 value transfer (system call)", + transfersValue: true, + valueTransferGas: 40000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + isSystemCall: true, + memorySize: 0, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + stateDb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) + stack := newstack() + + // Configure chain rules + config := *params.TestChainConfig + if tc.isEIP4762 { + verkleTime := uint64(0) + config.VerkleTime = &verkleTime + } + + blockCtx := BlockContext{ + BlockNumber: big.NewInt(1), + } + evm := NewEVM(blockCtx, stateDb, &config, Config{}) + + // Set chain rules based on test case + evm.chainRules.IsEIP158 = tc.isEIP158 + evm.chainRules.IsEIP4762 = tc.isEIP4762 + + // Setup target address + caller := common.Address{1} + targetAddr := common.Address{2} + + // Setup caller account + stateDb.CreateAccount(caller) + stateDb.SetBalance(caller, uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) + + if tc.targetExists { + if tc.targetEmpty { + stateDb.CreateAccount(targetAddr) + } else { + stateDb.CreateAccount(targetAddr) + stateDb.SetBalance(targetAddr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) + } + } + + // Setup contract + contractGas := uint64(100000) + contract := NewContract(caller, caller, new(uint256.Int), contractGas, nil) + contract.IsSystemCall = tc.isSystemCall + contract.Gas = contractGas + + // Setup stack: [value, address, gas] (bottom to top) + if tc.transfersValue { + stack.push(new(uint256.Int).SetUint64(1)) // value + } else { + stack.push(new(uint256.Int).SetUint64(0)) // value + } + stack.push(new(uint256.Int).SetBytes(targetAddr.Bytes())) // address + stack.push(new(uint256.Int).SetUint64(tc.valueTransferGas)) // gas + + // Setup two instances of memory to avoid side effects in `memoryGasCost` + mem := NewMemory() + memForExpected := NewMemory() + + // Mock AccessEvents for EIP4762 + if tc.isEIP4762 { + accessEvents := state.NewAccessEvents(stateDb.PointCache()) + evm.AccessEvents = accessEvents + // For testing, we'll need to ensure the access events returns the expected gas + // This might require setting up the state properly or mocking the behavior + } + + // Initialize expected multi gas with transfer gas value + expectedMultiGas := multigas.ComputationGas(tc.valueTransferGas) + + // Apply cahin rules + if tc.transfersValue && !tc.isEIP4762 { + expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallValueTransferGas) + } + + if tc.isEIP158 { + if tc.transfersValue && tc.targetEmpty { + expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) + } + } else if !tc.targetExists { + expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) + } + + // Call `memoryGasCost` to get the memory gas cost + memoryMultiGas, _, err := memoryGasCost(memForExpected, tc.memorySize) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + expectedMultiGas, _ = expectedMultiGas.SafeAdd(expectedMultiGas, memoryMultiGas) + + if tc.isEIP4762 && tc.transfersValue && !tc.isSystemCall { + valueTransferGas := evm.AccessEvents.ValueTransferGas(contract.Address(), caller) + overflow := expectedMultiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas) + if overflow { + t.Fatalf("Expected multi gas overflow for test case %s", tc.name) + } + } + + // Call the function + multiGas, _, err := gasCall(evm, contract, stack, mem, tc.memorySize) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if *multiGas != *expectedMultiGas { + t.Errorf("Expected multi gas %d, got %d", expectedMultiGas, multiGas) + } + }) + } +} From 01bcf641f4dbd4d58aea487b7eee09a697a4d720 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Mon, 14 Jul 2025 12:29:57 +0200 Subject: [PATCH 2/8] Instrument `gasCallCode` with multi gas and unify the test scenario --- core/vm/gas_table.go | 27 ++-- core/vm/operaions_gas_test.go | 283 +++++++++++++++++++++++----------- 2 files changed, 211 insertions(+), 99 deletions(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index d3b208407..95c734aba 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -440,7 +440,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize } } - // NOTE(NIT-3483): Should callGas take into account all gas or only the computation gas? + // NOTE(NIT-3483): using only the computation gas for callGas computationGas := multiGas.Get(multigas.ResourceKindComputation) evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, computationGas, stack.Back(0)) if err != nil { @@ -456,39 +456,46 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize } func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (*multigas.MultiGas, uint64, error) { - multiGas, memoryGas, err := memoryGasCost(mem, memorySize) + memoryMultiGas, _, err := memoryGasCost(mem, memorySize) if err != nil { return multigas.ZeroGas(), 0, err } var ( - gas uint64 + multiGas = multigas.ZeroGas() overflow bool ) if stack.Back(2).Sign() != 0 && !evm.chainRules.IsEIP4762 { - gas += params.CallValueTransferGas + multiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallValueTransferGas) } - // TODO(NIT-3484): Update multi dimensional gas here - if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { + multiGas, overflow = multiGas.SafeAdd(multiGas, memoryMultiGas) + if overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } if evm.chainRules.IsEIP4762 && !contract.IsSystemCall { address := common.Address(stack.Back(1).Bytes20()) transfersValue := !stack.Back(2).IsZero() if transfersValue { - gas, overflow = math.SafeAdd(gas, evm.AccessEvents.ValueTransferGas(contract.Address(), address)) + valueTransferGas := evm.AccessEvents.ValueTransferGas(contract.Address(), address) + overflow = multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas) if overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } } } - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + + // NOTE(NIT-3483): using only the computation gas for callGas + computationGas := multiGas.Get(multigas.ResourceKindComputation) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, computationGas, stack.Back(0)) if err != nil { return multigas.ZeroGas(), 0, err } - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + overflow = multiGas.SafeIncrement(multigas.ResourceKindComputation, evm.callGasTemp) + if overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - return multiGas, gas, nil + + singleGas, _ := multiGas.SingleGas() + return multiGas, singleGas, nil } func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (*multigas.MultiGas, uint64, error) { diff --git a/core/vm/operaions_gas_test.go b/core/vm/operaions_gas_test.go index e068eef1d..703c29f71 100644 --- a/core/vm/operaions_gas_test.go +++ b/core/vm/operaions_gas_test.go @@ -451,86 +451,20 @@ func TestGasSStore4762(t *testing.T) { } } -// CALL gas function test -func TestGasCall(t *testing.T) { - testCases := []struct { - name string - transfersValue bool - valueTransferGas uint64 - targetExists bool - targetEmpty bool - isEIP158 bool - isEIP4762 bool - isSystemCall bool - memorySize uint64 - }{ - { - name: "No value transfer, no memory expansion", - transfersValue: false, - valueTransferGas: 80000, - targetExists: true, - targetEmpty: false, - isEIP158: true, - isEIP4762: false, - isSystemCall: false, - memorySize: 500, - }, - { - name: "Value transfer to existing account", - transfersValue: true, - valueTransferGas: 70000, - targetExists: true, - targetEmpty: false, - isEIP158: true, - isEIP4762: false, - isSystemCall: false, - memorySize: 0, - }, - { - name: "Value transfer to empty account (EIP158)", - transfersValue: true, - valueTransferGas: 60000, - targetExists: true, - targetEmpty: true, - isEIP158: true, - isEIP4762: false, - isSystemCall: false, - memorySize: 0, - }, - { - name: "Non-existent account (pre-EIP158)", - transfersValue: false, - valueTransferGas: 55000, - targetExists: false, - targetEmpty: false, - isEIP158: false, - isEIP4762: false, - isSystemCall: false, - memorySize: 0, - }, - { - name: "EIP4762 value transfer (not system call)", - transfersValue: true, - valueTransferGas: 45000, - targetExists: true, - targetEmpty: false, - isEIP158: true, - isEIP4762: true, - isSystemCall: false, - memorySize: 0, - }, - { - name: "EIP4762 value transfer (system call)", - transfersValue: true, - valueTransferGas: 40000, - targetExists: true, - targetEmpty: false, - isEIP158: true, - isEIP4762: true, - isSystemCall: true, - memorySize: 0, - }, - } +type GasCallFuncTestCase struct { + name string // descriptive name for the test case + transfersValue bool // whether the call transfers value + valueTransferGas uint64 // gas argument passed on stack + targetExists bool // whether the target account exists + targetEmpty bool // whether the target account is empty (no balance/code) + isEIP158 bool // whether EIP-158 rules apply (empty account handling) + isEIP4762 bool // whether EIP-4762 rules apply (Verkle trees) + isSystemCall bool // whether this is a system call (bypasses some gas costs) + memorySize uint64 // memory size for the operation (triggers memory expansion) +} + +func testGasCallFuncFuncWithCases(t *testing.T, config *params.ChainConfig, gasCallFunc gasFunc, testCases []GasCallFuncTestCase, isCallCode bool) { + t.Helper() for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -538,7 +472,6 @@ func TestGasCall(t *testing.T) { stack := newstack() // Configure chain rules - config := *params.TestChainConfig if tc.isEIP4762 { verkleTime := uint64(0) config.VerkleTime = &verkleTime @@ -547,7 +480,7 @@ func TestGasCall(t *testing.T) { blockCtx := BlockContext{ BlockNumber: big.NewInt(1), } - evm := NewEVM(blockCtx, stateDb, &config, Config{}) + evm := NewEVM(blockCtx, stateDb, config, Config{}) // Set chain rules based on test case evm.chainRules.IsEIP158 = tc.isEIP158 @@ -593,8 +526,6 @@ func TestGasCall(t *testing.T) { if tc.isEIP4762 { accessEvents := state.NewAccessEvents(stateDb.PointCache()) evm.AccessEvents = accessEvents - // For testing, we'll need to ensure the access events returns the expected gas - // This might require setting up the state properly or mocking the behavior } // Initialize expected multi gas with transfer gas value @@ -605,12 +536,15 @@ func TestGasCall(t *testing.T) { expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallValueTransferGas) } - if tc.isEIP158 { - if tc.transfersValue && tc.targetEmpty { + // Account creation gas only applies to gasCall, not gasCallCode + if !isCallCode { + if tc.isEIP158 { + if tc.transfersValue && tc.targetEmpty { + expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) + } + } else if !tc.targetExists { expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) } - } else if !tc.targetExists { - expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) } // Call `memoryGasCost` to get the memory gas cost @@ -620,6 +554,7 @@ func TestGasCall(t *testing.T) { } expectedMultiGas, _ = expectedMultiGas.SafeAdd(expectedMultiGas, memoryMultiGas) + // EIP4762 storage access gas for value transfers if tc.isEIP4762 && tc.transfersValue && !tc.isSystemCall { valueTransferGas := evm.AccessEvents.ValueTransferGas(contract.Address(), caller) overflow := expectedMultiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas) @@ -629,7 +564,7 @@ func TestGasCall(t *testing.T) { } // Call the function - multiGas, _, err := gasCall(evm, contract, stack, mem, tc.memorySize) + multiGas, _, err := gasCallFunc(evm, contract, stack, mem, tc.memorySize) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -640,3 +575,173 @@ func TestGasCall(t *testing.T) { }) } } + +// CALL gas function test +func TestGasCall(t *testing.T) { + testCases := []GasCallFuncTestCase{ + { + name: "No value transfer with memory expansion", + transfersValue: false, + valueTransferGas: 80000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + memorySize: 500, + }, + { + name: "Value transfer to existing account", + transfersValue: true, + valueTransferGas: 70000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + memorySize: 0, + }, + { + name: "Value transfer to empty account (EIP158)", + transfersValue: true, + valueTransferGas: 60000, + targetExists: true, + targetEmpty: true, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + memorySize: 0, + }, + { + name: "Non-existent account (pre-EIP158)", + transfersValue: false, + valueTransferGas: 55000, + targetExists: false, + targetEmpty: false, + isEIP158: false, + isEIP4762: false, + isSystemCall: false, + memorySize: 0, + }, + { + name: "EIP4762 value transfer (not system call)", + transfersValue: true, + valueTransferGas: 45000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + isSystemCall: false, + memorySize: 0, + }, + { + name: "EIP4762 value transfer (system call)", + transfersValue: true, + valueTransferGas: 40000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + isSystemCall: true, + memorySize: 0, + }, + { + name: "EIP4762 no value transfer with memory", + transfersValue: false, + valueTransferGas: 35000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + isSystemCall: false, + memorySize: 256, + }, + } + testGasCallFuncFuncWithCases(t, params.TestChainConfig, gasCall, testCases, false) +} + +// CALLCODE gas function test +func TestGasCallCode(t *testing.T) { + // NOTE: targetExists/targetEmpty fields don't affect gasCallCode but kept for consistency + testCases := []GasCallFuncTestCase{ + { + name: "No value transfer with memory expansion", + transfersValue: false, + valueTransferGas: 80000, + memorySize: 500, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + }, + { + name: "Value transfer (pre-EIP4762)", + transfersValue: true, + valueTransferGas: 70000, + memorySize: 0, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + }, + { + name: "Value transfer with memory expansion", + transfersValue: true, + valueTransferGas: 65000, + memorySize: 256, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isSystemCall: false, + }, + { + name: "EIP4762 value transfer (not system call)", + transfersValue: true, + valueTransferGas: 45000, + memorySize: 0, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + isSystemCall: false, + }, + { + name: "EIP4762 value transfer (system call)", + transfersValue: true, + valueTransferGas: 40000, + memorySize: 0, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + isSystemCall: true, + }, + { + name: "EIP4762 no value transfer with memory", + transfersValue: false, + valueTransferGas: 50000, + memorySize: 128, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + isSystemCall: false, + }, + { + name: "Pre-EIP158 with value transfer", + transfersValue: true, + valueTransferGas: 55000, + memorySize: 0, + targetExists: true, + targetEmpty: false, + isEIP158: false, + isEIP4762: false, + isSystemCall: false, + }, + } + + testGasCallFuncFuncWithCases(t, params.TestChainConfig, gasCallCode, testCases, true) +} From c0bc014f9276932e530937c74945a6beeb83041e Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Mon, 14 Jul 2025 14:08:59 +0200 Subject: [PATCH 3/8] Instrument `makeCallVariantGasCallEIP2929` with multi gas --- core/vm/gas_table.go | 12 +++----- core/vm/operaions_gas_test.go | 56 ++++++++++++++++++++++++++++++++--- core/vm/operations_acl.go | 11 +++++-- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 95c734aba..de846bfa0 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -433,8 +433,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize if evm.chainRules.IsEIP4762 && !contract.IsSystemCall { if transfersValue { valueTransferGas := evm.AccessEvents.ValueTransferGas(contract.Address(), address) - overflow := multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas) - if overflow { + if overflow := multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } } @@ -446,8 +445,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize if err != nil { return multigas.ZeroGas(), 0, err } - overflow = multiGas.SafeIncrement(multigas.ResourceKindComputation, evm.callGasTemp) - if overflow { + if overflow = multiGas.SafeIncrement(multigas.ResourceKindComputation, evm.callGasTemp); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } @@ -476,8 +474,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory transfersValue := !stack.Back(2).IsZero() if transfersValue { valueTransferGas := evm.AccessEvents.ValueTransferGas(contract.Address(), address) - overflow = multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas) - if overflow { + if overflow = multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } } @@ -489,8 +486,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory if err != nil { return multigas.ZeroGas(), 0, err } - overflow = multiGas.SafeIncrement(multigas.ResourceKindComputation, evm.callGasTemp) - if overflow { + if overflow = multiGas.SafeIncrement(multigas.ResourceKindComputation, evm.callGasTemp); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } diff --git a/core/vm/operaions_gas_test.go b/core/vm/operaions_gas_test.go index 703c29f71..a7c695b1b 100644 --- a/core/vm/operaions_gas_test.go +++ b/core/vm/operaions_gas_test.go @@ -453,12 +453,14 @@ func TestGasSStore4762(t *testing.T) { type GasCallFuncTestCase struct { name string // descriptive name for the test case + slotInAccessList bool // whether the slot is in the access list transfersValue bool // whether the call transfers value valueTransferGas uint64 // gas argument passed on stack targetExists bool // whether the target account exists targetEmpty bool // whether the target account is empty (no balance/code) isEIP158 bool // whether EIP-158 rules apply (empty account handling) isEIP4762 bool // whether EIP-4762 rules apply (Verkle trees) + isEIP2929 bool // whether EIP-2929 rules apply (access lists) isSystemCall bool // whether this is a system call (bypasses some gas costs) memorySize uint64 // memory size for the operation (triggers memory expansion) } @@ -466,6 +468,9 @@ type GasCallFuncTestCase struct { func testGasCallFuncFuncWithCases(t *testing.T, config *params.ChainConfig, gasCallFunc gasFunc, testCases []GasCallFuncTestCase, isCallCode bool) { t.Helper() + contractGas := uint64(100000) + slotKey := common.HexToHash("0xdeadbeef") // any dummy key + for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { stateDb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) @@ -503,8 +508,11 @@ func testGasCallFuncFuncWithCases(t *testing.T, config *params.ChainConfig, gasC } } + if tc.slotInAccessList { + stateDb.AddSlotToAccessList(targetAddr, slotKey) + } + // Setup contract - contractGas := uint64(100000) contract := NewContract(caller, caller, new(uint256.Int), contractGas, nil) contract.IsSystemCall = tc.isSystemCall contract.Gas = contractGas @@ -531,13 +539,19 @@ func testGasCallFuncFuncWithCases(t *testing.T, config *params.ChainConfig, gasC // Initialize expected multi gas with transfer gas value expectedMultiGas := multigas.ComputationGas(tc.valueTransferGas) + // For EIP-2929 (access lists) + wasColdAccess := !tc.isEIP2929 || !evm.StateDB.AddressInAccessList(targetAddr) + if tc.isEIP2929 && wasColdAccess && !tc.slotInAccessList { + expectedMultiGas.SafeIncrement(multigas.ResourceKindStorageAccess, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929) + } + // Apply cahin rules if tc.transfersValue && !tc.isEIP4762 { expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallValueTransferGas) } // Account creation gas only applies to gasCall, not gasCallCode - if !isCallCode { + if !isCallCode && wasColdAccess { if tc.isEIP158 { if tc.transfersValue && tc.targetEmpty { expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) @@ -557,8 +571,7 @@ func testGasCallFuncFuncWithCases(t *testing.T, config *params.ChainConfig, gasC // EIP4762 storage access gas for value transfers if tc.isEIP4762 && tc.transfersValue && !tc.isSystemCall { valueTransferGas := evm.AccessEvents.ValueTransferGas(contract.Address(), caller) - overflow := expectedMultiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas) - if overflow { + if overflow := expectedMultiGas.SafeIncrement(multigas.ResourceKindStorageAccess, valueTransferGas); overflow { t.Fatalf("Expected multi gas overflow for test case %s", tc.name) } } @@ -745,3 +758,38 @@ func TestGasCallCode(t *testing.T) { testGasCallFuncFuncWithCases(t, params.TestChainConfig, gasCallCode, testCases, true) } + +// CALL decorated with makeCallVariantGasCallEIP2929 gas function test +func TestGasCallEIP2929(t *testing.T) { + testCases := []GasCallFuncTestCase{ + { + name: "Cold access to existing account", + slotInAccessList: false, + transfersValue: false, + valueTransferGas: 80000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isEIP2929: true, + isSystemCall: false, + memorySize: 0, + }, + { + name: "Warm access (repeated)", + slotInAccessList: true, + transfersValue: false, + valueTransferGas: 80000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: false, + isEIP2929: true, + isSystemCall: false, + memorySize: 0, + }, + } + + gasCallEIP2929 = makeCallVariantGasCallEIP2929(gasCall, 1) + testGasCallFuncFuncWithCases(t, params.TestChainConfig, gasCallEIP2929, testCases, false) +} diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 5b9dd903b..1f574dcb9 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -194,12 +194,19 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g // also become correctly reported to tracers. contract.Gas += coldCost - // TODO(NIT-3484): Update multi dimensional gas here + if overflow := multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, coldCost); overflow { + return multigas.ZeroGas(), 0, ErrGasUintOverflow + } + + // FIXME(NIT-3483): this is the temporary workaround until all possible options for oldCalculators are instrumented (e.g DELEGATECALL, STATICCALL) + // for now, we calc single-dimensional gas separately to make `BlockchainTest` pass with history data + // singleGas, _ := multiGas.SingleGas() + // return multiGas, singleGas, nil var overflow bool if gas, overflow = math.SafeAdd(gas, coldCost); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - return multigas.ZeroGas(), gas, nil + return multiGas, gas, nil } } From 983b1fa7d0136971e159410f16a25dd5343e23e2 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Mon, 14 Jul 2025 14:29:02 +0200 Subject: [PATCH 4/8] Fixup gas operations test name --- core/vm/{operaions_gas_test.go => operations_gas_test.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/vm/{operaions_gas_test.go => operations_gas_test.go} (100%) diff --git a/core/vm/operaions_gas_test.go b/core/vm/operations_gas_test.go similarity index 100% rename from core/vm/operaions_gas_test.go rename to core/vm/operations_gas_test.go From d694447680673f0ed32f0fb2e3c315ee83771681 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Mon, 14 Jul 2025 15:49:38 +0200 Subject: [PATCH 5/8] Instrument `makeCallVariantGasEIP4762` with multi gas --- core/vm/operations_gas_test.go | 41 +++++++++++++++++++++++++++++++++- core/vm/operations_verkle.go | 8 ++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/core/vm/operations_gas_test.go b/core/vm/operations_gas_test.go index a7c695b1b..1dd20c01a 100644 --- a/core/vm/operations_gas_test.go +++ b/core/vm/operations_gas_test.go @@ -460,6 +460,7 @@ type GasCallFuncTestCase struct { targetEmpty bool // whether the target account is empty (no balance/code) isEIP158 bool // whether EIP-158 rules apply (empty account handling) isEIP4762 bool // whether EIP-4762 rules apply (Verkle trees) + addWitnessGas bool // whether to add witness gas for EIP-4762 isEIP2929 bool // whether EIP-2929 rules apply (access lists) isSystemCall bool // whether this is a system call (bypasses some gas costs) memorySize uint64 // memory size for the operation (triggers memory expansion) @@ -576,6 +577,12 @@ func testGasCallFuncFuncWithCases(t *testing.T, config *params.ChainConfig, gasC } } + // For EIP-4762 (Witnesses gas) + if tc.addWitnessGas && !contract.IsSystemCall { + // Calculated in `touchAddressAndChargeGas` WitnessBranchReadCost + WitnessChunkReadCost = 2100 + expectedMultiGas.SafeIncrement(multigas.ResourceKindStorageAccess, 2100) + } + // Call the function multiGas, _, err := gasCallFunc(evm, contract, stack, mem, tc.memorySize) if err != nil { @@ -760,7 +767,7 @@ func TestGasCallCode(t *testing.T) { } // CALL decorated with makeCallVariantGasCallEIP2929 gas function test -func TestGasCallEIP2929(t *testing.T) { +func TestCallVariantGasCallEIP2929(t *testing.T) { testCases := []GasCallFuncTestCase{ { name: "Cold access to existing account", @@ -793,3 +800,35 @@ func TestGasCallEIP2929(t *testing.T) { gasCallEIP2929 = makeCallVariantGasCallEIP2929(gasCall, 1) testGasCallFuncFuncWithCases(t, params.TestChainConfig, gasCallEIP2929, testCases, false) } + +func TestVariantGasEIP4762(t *testing.T) { + testCases := []GasCallFuncTestCase{ + { + name: "EIP4762 non-system call with witness cost", + transfersValue: false, + valueTransferGas: 50000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + addWitnessGas: true, + isSystemCall: false, + memorySize: 64, + }, + { + name: "EIP4762 system call skips witness cost", + transfersValue: false, + valueTransferGas: 50000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP4762: true, + addWitnessGas: true, + isSystemCall: true, + memorySize: 64, + }, + } + + gasCallEIP4762 = makeCallVariantGasEIP4762(gasCallCode) + testGasCallFuncFuncWithCases(t, params.TestChainConfig, gasCallEIP4762, testCases, true) +} diff --git a/core/vm/operations_verkle.go b/core/vm/operations_verkle.go index 9222821ea..4324f5121 100644 --- a/core/vm/operations_verkle.go +++ b/core/vm/operations_verkle.go @@ -93,16 +93,18 @@ func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc { return multigas.ZeroGas(), 0, err } if contract.IsSystemCall { - return multigas.ZeroGas(), gas, nil + return multiGas, gas, nil } if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile { - return multigas.ZeroGas(), gas, nil + return multiGas, gas, nil } witnessGas := evm.AccessEvents.MessageCallGas(contract.Address()) if witnessGas == 0 { witnessGas = params.WarmStorageReadCostEIP2929 } - return multiGas, witnessGas + gas, nil + multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, witnessGas) + singleGas, _ := multiGas.SingleGas() + return multiGas, singleGas, nil } } From 5e785610f691c2d494e2cbda3b61e2749222c812 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Tue, 15 Jul 2025 12:43:49 +0200 Subject: [PATCH 6/8] Instrument `gasDelegateCall` and `gasStaticCall` with multi gas --- core/vm/gas_table.go | 16 +++++----- core/vm/operations_gas_test.go | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index de846bfa0..dda8ce655 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -503,12 +503,12 @@ func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me if err != nil { return multigas.ZeroGas(), 0, err } - var overflow bool - // TODO(NIT-3484): Update multi dimensional gas here - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + if overflow := multiGas.SafeIncrement(multigas.ResourceKindComputation, evm.callGasTemp); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - return multiGas, gas, nil + + singleGas, _ := multiGas.SingleGas() + return multiGas, singleGas, nil } func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (*multigas.MultiGas, uint64, error) { @@ -520,12 +520,12 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo if err != nil { return multigas.ZeroGas(), 0, err } - var overflow bool - // TODO(NIT-3484): Update multi dimensional gas here - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + if overflow := multiGas.SafeIncrement(multigas.ResourceKindComputation, evm.callGasTemp); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - return multiGas, gas, nil + + singleGas, _ := multiGas.SingleGas() + return multiGas, singleGas, nil } func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (*multigas.MultiGas, uint64, error) { diff --git a/core/vm/operations_gas_test.go b/core/vm/operations_gas_test.go index 1dd20c01a..4cc6302a2 100644 --- a/core/vm/operations_gas_test.go +++ b/core/vm/operations_gas_test.go @@ -832,3 +832,56 @@ func TestVariantGasEIP4762(t *testing.T) { gasCallEIP4762 = makeCallVariantGasEIP4762(gasCallCode) testGasCallFuncFuncWithCases(t, params.TestChainConfig, gasCallEIP4762, testCases, true) } + +func testGasDelegateOrStaticCall(t *testing.T, gasImplFunc gasFunc) { + t.Helper() + + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) + evm := NewEVM(BlockContext{}, statedb, params.TestChainConfig, Config{}) + + caller := common.Address{} + contractAddr := common.Address{1} + contractGas := uint64(100000) + contract := NewContract(caller, contractAddr, new(uint256.Int), contractGas, nil) + + stack := newstack() + mem := NewMemory() + memForExpected := NewMemory() + + stack.push(new(uint256.Int).SetUint64(50000)) + memorySize := uint64(64) + + expectedMultiGas, memorySingleGas, err := memoryGasCost(memForExpected, memorySize) + if err != nil { + t.Fatalf("Failed memoryGasCost: %v", err) + } + + callGas, err := callGas(evm.chainRules.IsEIP150, contractGas, memorySingleGas, stack.Back(0)) + if err != nil { + t.Fatalf("Failed callGas: %v", err) + } + + expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, callGas) + expectedSingleGas := memorySingleGas + callGas + + // Call gasImplFunc + multiGas, singleGas, err := gasImplFunc(evm, contract, stack, mem, memorySize) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if *multiGas != *expectedMultiGas { + t.Errorf("Expected multi gas %d, got %d", expectedMultiGas, multiGas) + } + if singleGas != expectedSingleGas { + t.Errorf("Expected single gas %d, got %d", expectedSingleGas, singleGas) + } +} + +func TestGasDelegateCall(t *testing.T) { + testGasDelegateOrStaticCall(t, gasDelegateCall) +} + +func TestGasStaticCall(t *testing.T) { + testGasDelegateOrStaticCall(t, gasStaticCall) +} From 2661c9195b55dc71d8a344dd59167b941912f64c Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Tue, 15 Jul 2025 13:18:15 +0200 Subject: [PATCH 7/8] Instrument `makeCallVariantGasCallEIP7702` with multi gas --- core/vm/operations_acl.go | 27 ++++++-------- core/vm/operations_gas_test.go | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 16 deletions(-) diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 1f574dcb9..dc809cc6b 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -198,15 +198,8 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g return multigas.ZeroGas(), 0, ErrGasUintOverflow } - // FIXME(NIT-3483): this is the temporary workaround until all possible options for oldCalculators are instrumented (e.g DELEGATECALL, STATICCALL) - // for now, we calc single-dimensional gas separately to make `BlockchainTest` pass with history data - // singleGas, _ := multiGas.SingleGas() - // return multiGas, singleGas, nil - var overflow bool - if gas, overflow = math.SafeAdd(gas, coldCost); overflow { - return multigas.ZeroGas(), 0, ErrGasUintOverflow - } - return multiGas, gas, nil + singleGas, _ := multiGas.SingleGas() + return multiGas, singleGas, nil } } @@ -272,8 +265,8 @@ var ( func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc { return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (*multigas.MultiGas, uint64, error) { var ( - total uint64 // total dynamic gas used - addr = common.Address(stack.Back(1).Bytes20()) + multiGas = multigas.ZeroGas() // total dynamic gas used + addr = common.Address(stack.Back(1).Bytes20()) ) // Check slot presence in the access list @@ -287,7 +280,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc { if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { return multigas.ZeroGas(), 0, ErrOutOfGas } - total += coldCost + multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, coldCost) } // Check if code is a delegation and if so, charge for resolution. @@ -302,7 +295,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc { if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { return multigas.ZeroGas(), 0, ErrOutOfGas } - total += cost + multiGas.SafeIncrement(multigas.ResourceKindStorageAccess, cost) } // Now call the old calculator, which takes into account @@ -319,12 +312,14 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc { // adding it to the return, it will be charged outside of this function, as // part of the dynamic gas. This will ensure it is correctly reported to // tracers. - contract.Gas += total + contract.Gas += multiGas.Get(multigas.ResourceKindStorageAccess) var overflow bool - if total, overflow = math.SafeAdd(old, total); overflow { + if multiGas, overflow = multiGas.SafeAdd(multiGas, multiOld); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - return multigas.ZeroGas(), total, nil + + singleGas, _ := multiGas.SingleGas() + return multiGas, singleGas, nil } } diff --git a/core/vm/operations_gas_test.go b/core/vm/operations_gas_test.go index 4cc6302a2..64031d827 100644 --- a/core/vm/operations_gas_test.go +++ b/core/vm/operations_gas_test.go @@ -833,6 +833,74 @@ func TestVariantGasEIP4762(t *testing.T) { testGasCallFuncFuncWithCases(t, params.TestChainConfig, gasCallEIP4762, testCases, true) } +func TestCallVariantGasCallEIP7702(t *testing.T) { + testCases := []GasCallFuncTestCase{ + { + name: "7702 cold access, non-delegate, no value", + slotInAccessList: false, + transfersValue: false, + valueTransferGas: 50000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP2929: true, + isSystemCall: false, + memorySize: 128, + }, + { + name: "7702 warm access, with value transfer", + slotInAccessList: true, + transfersValue: true, + valueTransferGas: 60000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP2929: true, + isSystemCall: false, + memorySize: 64, + }, + { + name: "7702 cold access, empty account, value transfer", + slotInAccessList: false, + transfersValue: true, + valueTransferGas: 55000, + targetExists: true, + targetEmpty: true, + isEIP158: true, + isEIP2929: true, + isSystemCall: false, + memorySize: 0, + }, + { + name: "7702 no value, warm slot", + slotInAccessList: true, + transfersValue: false, + valueTransferGas: 45000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP2929: true, + isSystemCall: false, + memorySize: 32, + }, + { + name: "7702 system call skips access gas", + slotInAccessList: false, + transfersValue: false, + valueTransferGas: 40000, + targetExists: true, + targetEmpty: false, + isEIP158: true, + isEIP2929: true, + isSystemCall: true, + memorySize: 16, + }, + } + + wrapped := makeCallVariantGasCallEIP7702(gasCall) + testGasCallFuncFuncWithCases(t, params.TestChainConfig, wrapped, testCases, false) +} + func testGasDelegateOrStaticCall(t *testing.T, gasImplFunc gasFunc) { t.Helper() From 0665b849c940854459953f559e1c21cd772f90c2 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Tue, 15 Jul 2025 15:32:11 +0200 Subject: [PATCH 8/8] Fix resource kind and callGas parameter in `gasCall` and `gasCallCode` --- core/vm/gas_table.go | 18 ++++++++---------- core/vm/operations_gas_test.go | 4 ++-- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index dda8ce655..1bf07e5af 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -411,10 +411,10 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize if evm.chainRules.IsEIP158 { if transfersValue && evm.StateDB.Empty(address) { - multiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) + multiGas.SafeIncrement(multigas.ResourceKindStorageGrowth, params.CallNewAccountGas) } } else if !evm.StateDB.Exist(address) { - multiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) + multiGas.SafeIncrement(multigas.ResourceKindStorageGrowth, params.CallNewAccountGas) } if transfersValue && !evm.chainRules.IsEIP4762 { @@ -439,9 +439,8 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize } } - // NOTE(NIT-3483): using only the computation gas for callGas - computationGas := multiGas.Get(multigas.ResourceKindComputation) - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, computationGas, stack.Back(0)) + singleGas, _ := multiGas.SingleGas() + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, singleGas, stack.Back(0)) if err != nil { return multigas.ZeroGas(), 0, err } @@ -449,7 +448,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize return multigas.ZeroGas(), 0, ErrGasUintOverflow } - singleGas, _ := multiGas.SingleGas() + singleGas, _ = multiGas.SingleGas() return multiGas, singleGas, nil } @@ -480,9 +479,8 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory } } - // NOTE(NIT-3483): using only the computation gas for callGas - computationGas := multiGas.Get(multigas.ResourceKindComputation) - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, computationGas, stack.Back(0)) + singleGas, _ := multiGas.SingleGas() + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, singleGas, stack.Back(0)) if err != nil { return multigas.ZeroGas(), 0, err } @@ -490,7 +488,7 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory return multigas.ZeroGas(), 0, ErrGasUintOverflow } - singleGas, _ := multiGas.SingleGas() + singleGas, _ = multiGas.SingleGas() return multiGas, singleGas, nil } diff --git a/core/vm/operations_gas_test.go b/core/vm/operations_gas_test.go index 64031d827..ff9ea9b27 100644 --- a/core/vm/operations_gas_test.go +++ b/core/vm/operations_gas_test.go @@ -555,10 +555,10 @@ func testGasCallFuncFuncWithCases(t *testing.T, config *params.ChainConfig, gasC if !isCallCode && wasColdAccess { if tc.isEIP158 { if tc.transfersValue && tc.targetEmpty { - expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) + expectedMultiGas.SafeIncrement(multigas.ResourceKindStorageGrowth, params.CallNewAccountGas) } } else if !tc.targetExists { - expectedMultiGas.SafeIncrement(multigas.ResourceKindComputation, params.CallNewAccountGas) + expectedMultiGas.SafeIncrement(multigas.ResourceKindStorageGrowth, params.CallNewAccountGas) } }