diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 7d8dd8b4b..dabf1e768 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -258,16 +258,20 @@ func makeGasLog(n uint64) gasFunc { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - multiGas, gas, err := memoryGasCost(mem, memorySize) + multiGas, _, err := memoryGasCost(mem, memorySize) if err != nil { return multigas.ZeroGas(), 0, err } - // TODO(NIT-3484): Update multi dimensional gas here - if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { + // Base LOG operation considered as computation. + // See rationale in: https://github.com/OffchainLabs/nitro/blob/master/docs/decisions/0002-multi-dimensional-gas-metering.md + if overflow = multiGas.SafeIncrement(multigas.ResourceKindComputation, params.LogGas); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { + + // LOG topic operations considered as computation. + // See rationale in: https://github.com/OffchainLabs/nitro/blob/master/docs/decisions/0002-multi-dimensional-gas-metering.md + if overflow = multiGas.SafeIncrement(multigas.ResourceKindComputation, n*params.LogTopicGas); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } @@ -275,10 +279,13 @@ func makeGasLog(n uint64) gasFunc { if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { + // Event log data considered as history growth. + // See rationale in: https://github.com/OffchainLabs/nitro/blob/master/docs/decisions/0002-multi-dimensional-gas-metering.md + if overflow = multiGas.SafeIncrement(multigas.ResourceKindHistoryGrowth, memorySizeGas); overflow { return multigas.ZeroGas(), 0, ErrGasUintOverflow } - return multiGas, gas, 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 cf8754e87..e1046aa71 100644 --- a/core/vm/operations_gas_test.go +++ b/core/vm/operations_gas_test.go @@ -1260,3 +1260,47 @@ func TestGasSelfdestructEIP4762(t *testing.T) { t.Errorf("Expected multi gas %d, got %d", expectedMultiGas, multiGas) } } + +// Base LOG0-LOG4 gas function test +func TestMakeGasLog(t *testing.T) { + for n := uint64(0); n <= 4; n++ { + 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() + + // Set up stack for LOG operation + requestedSize := uint64(32) // requestedSize = 32 bytes for data + stack.push(new(uint256.Int).SetUint64(requestedSize)) // stack.Back(1) + stack.push(new(uint256.Int)) // dummy top (stack.Back(0)) + + // memorySize is arbitrary, only affects memory cost component + memorySize := uint64(64) + + _, memorySingleGas, err := memoryGasCost(memForExpected, memorySize) + if err != nil { + t.Fatalf("Failed memoryGasCost: %v", err) + } + + expectedComputation := memorySingleGas + params.LogGas + n*params.LogTopicGas + expectedHistory := requestedSize * params.LogDataGas + + expectedMultiGas := multigas.ComputationGas(expectedComputation).Set(multigas.ResourceKindHistoryGrowth, expectedHistory) + + multiGas, _, err := makeGasLog(n)(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) + } + } +}