diff --git a/core/state_transition.go b/core/state_transition.go index 084985ffd4..297e8580ee 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -242,11 +242,12 @@ func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, err // 5. Run Script section // 6. Derive new state root type stateTransition struct { - gp *GasPool - msg *Message - gasRemaining vm.GasBudget - state vm.StateDB - evm *vm.EVM + gp *GasPool + msg *Message + initialBudget vm.GasBudget + gasRemaining vm.GasBudget + state vm.StateDB + evm *vm.EVM } // newStateTransition initialises and returns a new state transition object. @@ -304,6 +305,7 @@ func (st *stateTransition) buyGas() error { st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance) } st.gasRemaining = vm.NewGasBudget(st.msg.GasLimit) + st.initialBudget = st.gasRemaining.Copy() mgvalU256, _ := uint256.FromBig(mgval) st.state.SubBalance(st.msg.From, mgvalU256, tracing.BalanceDecreaseGasBuy) @@ -552,7 +554,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { // Return gas to the gas pool if rules.IsAmsterdam { // Refund is excluded for returning - err = st.gp.ReturnGas(st.gasRemaining.InitialGas-peakGasUsed, st.gasUsed()) + err = st.gp.ReturnGas(st.initialBudget.RegularGas-peakGasUsed, st.gasUsed()) } else { // Refund is included for returning err = st.gp.ReturnGas(st.gasRemaining.RegularGas, st.gasUsed()) @@ -684,7 +686,7 @@ func (st *stateTransition) returnGas() { // gasUsed returns the amount of gas used up by the state transition. func (st *stateTransition) gasUsed() uint64 { - return st.gasRemaining.Used() + return st.gasRemaining.Used(st.initialBudget) } // blobGasUsed returns the amount of blob gas used by the message. diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 48903561ec..16ce651a7d 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -97,12 +97,12 @@ func TestEIP2200(t *testing.T) { Transfer: func(StateDB, common.Address, common.Address, *uint256.Int, *params.Rules) {}, } evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) - - _, leftOver, err := evm.Call(common.Address{}, address, nil, NewGasBudget(tt.gaspool), new(uint256.Int)) + initialGas := NewGasBudget(tt.gaspool) + _, leftOver, err := evm.Call(common.Address{}, address, nil, initialGas.Copy(), new(uint256.Int)) if !errors.Is(err, tt.failure) { t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) } - if used := leftOver.Used(); used != tt.used { + if used := leftOver.Used(initialGas); used != tt.used { t.Errorf("test %d: gas used mismatch: have %v, want %v", i, used, tt.used) } if refund := evm.StateDB.GetRefund(); refund != tt.refund { @@ -157,11 +157,12 @@ func TestCreateGas(t *testing.T) { } evm := NewEVM(vmctx, statedb, chainConfig, config) - ret, leftOver, err := evm.Call(common.Address{}, address, nil, NewGasBudget(uint64(testGas)), new(uint256.Int)) + initialGas := NewGasBudget(uint64(testGas)) + ret, leftOver, err := evm.Call(common.Address{}, address, nil, initialGas.Copy(), new(uint256.Int)) if err != nil { return false } - gasUsed = leftOver.Used() + gasUsed = leftOver.Used(initialGas) if len(ret) != 32 { t.Fatalf("test %d: expected 32 bytes returned, have %d", i, len(ret)) } diff --git a/core/vm/gascosts.go b/core/vm/gascosts.go index bcc678c508..cc90c54798 100644 --- a/core/vm/gascosts.go +++ b/core/vm/gascosts.go @@ -43,17 +43,16 @@ func (g GasCosts) String() string { type GasBudget struct { RegularGas uint64 // The leftover gas for execution and state gas usage StateGas uint64 // The state gas reservoir - InitialGas uint64 // records the starting allowance for usage tracking } // NewGasBudget creates a GasBudget with the given initial regular gas allowance. func NewGasBudget(gas uint64) GasBudget { - return GasBudget{RegularGas: gas, InitialGas: gas} + return GasBudget{RegularGas: gas} } // Used returns the amount of regular gas consumed so far. -func (g GasBudget) Used() uint64 { - return g.InitialGas - g.RegularGas +func (g GasBudget) Used(initial GasBudget) uint64 { + return initial.RegularGas - g.RegularGas } // Exhaust sets all remaining gas to zero, preserving the initial amount @@ -63,6 +62,10 @@ func (g *GasBudget) Exhaust() { g.StateGas = 0 } +func (g *GasBudget) Copy() GasBudget { + return GasBudget{RegularGas: g.RegularGas, StateGas: g.StateGas} +} + // String returns a visual representation of the gas budget vector. func (g GasBudget) String() string { return fmt.Sprintf("<%v,%v>", g.RegularGas, g.StateGas) diff --git a/tests/state_test.go b/tests/state_test.go index 410db80096..e9b6ea1ba4 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -315,8 +315,10 @@ func runBenchmark(b *testing.B, t *StateTest) { b.StartTimer() start := time.Now() + initialGas := vm.NewGasBudget(msg.GasLimit) + // Execute the message. - _, leftOverGas, err := evm.Call(sender.Address(), *msg.To, msg.Data, vm.NewGasBudget(msg.GasLimit), uint256.MustFromBig(msg.Value)) + _, leftOverGas, err := evm.Call(sender.Address(), *msg.To, msg.Data, initialGas.Copy(), uint256.MustFromBig(msg.Value)) if err != nil { b.Error(err) return @@ -325,7 +327,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.StopTimer() elapsed += uint64(time.Since(start)) refund += state.StateDB.GetRefund() - gasUsed += leftOverGas.Used() + gasUsed += leftOverGas.Used(initialGas) state.StateDB.RevertToSnapshot(snapshot) }