core: apply fixes for 8037

This commit is contained in:
Marius van der Wijden 2026-04-22 19:24:44 +02:00 committed by Jared Wasinger
parent f6105d7610
commit a785c7c662
4 changed files with 45 additions and 28 deletions

View file

@ -609,14 +609,16 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
// On outer level tx failure, no state is written. // On outer level tx failure, no state is written.
if rules.IsAmsterdam && vmerr != nil { if rules.IsAmsterdam && vmerr != nil {
st.gasRemaining.StateGas += execGasUsed.StateGas if execGasUsed.StateGas > 0 {
st.gasRemaining.StateGas += uint64(execGasUsed.StateGas)
}
execGasUsed.StateGas = 0 execGasUsed.StateGas = 0
} }
// Refund costs for selfdestructed accounts and slots. // Refund costs for selfdestructed accounts and slots.
if rules.IsAmsterdam && vmerr == nil { if rules.IsAmsterdam && vmerr == nil {
cpsb := st.evm.Context.CostPerGasByte cpsb := st.evm.Context.CostPerGasByte
stateGasUsed := execGasUsed.StateGas + cost.StateGas stateGasUsed := int64(cost.StateGas) + execGasUsed.StateGas
var sdRefund uint64 var sdRefund uint64
for _, addr := range st.state.SameTxSelfDestructs() { for _, addr := range st.state.SameTxSelfDestructs() {
r := params.AccountCreationSize * cpsb r := params.AccountCreationSize * cpsb
@ -624,15 +626,22 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
r += uint64(st.state.GetCodeSize(addr)) * cpsb r += uint64(st.state.GetCodeSize(addr)) * cpsb
sdRefund += r sdRefund += r
} }
if sdRefund > stateGasUsed { if stateGasUsed < 0 {
sdRefund = stateGasUsed sdRefund = 0
} else if sdRefund > uint64(stateGasUsed) {
sdRefund = uint64(stateGasUsed)
} }
if sdRefund > 0 { if sdRefund > 0 {
st.gasRemaining.StateGas += sdRefund st.gasRemaining.StateGas += sdRefund
if execGasUsed.StateGas >= sdRefund { if execGasUsed.StateGas >= int64(sdRefund) {
execGasUsed.StateGas -= sdRefund execGasUsed.StateGas -= int64(sdRefund)
} else { } else {
extra := sdRefund - execGasUsed.StateGas var extra uint64
if execGasUsed.StateGas > 0 {
extra = sdRefund - uint64(execGasUsed.StateGas)
} else {
extra = sdRefund
}
execGasUsed.StateGas = 0 execGasUsed.StateGas = 0
if cost.StateGas >= extra { if cost.StateGas >= extra {
cost.StateGas -= extra cost.StateGas -= extra
@ -673,7 +682,12 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
// EIP-8037: 2D gas accounting for Amsterdam. // EIP-8037: 2D gas accounting for Amsterdam.
// tx_regular = intrinsic_regular + exec_regular_gas_used // tx_regular = intrinsic_regular + exec_regular_gas_used
// tx_state = intrinsic_state (adjusted) + exec_state_gas_used // tx_state = intrinsic_state (adjusted) + exec_state_gas_used
txState := cost.StateGas + execGasUsed.StateGas // execGasUsed.StateGas may be negative when an SSTORE 0→x→0 refund
// exceeded the intrinsic-charged state gas
txState := cost.StateGas
if execGasUsed.StateGas > 0 {
txState += uint64(execGasUsed.StateGas)
}
txRegular := cost.RegularGas + execGasUsed.RegularGas txRegular := cost.RegularGas + execGasUsed.RegularGas
txRegular = max(txRegular, floorDataGas) txRegular = max(txRegular, floorDataGas)
if err := st.gp.ReturnGasAmsterdam(txRegular, txState, st.gasUsed()); err != nil { if err := st.gp.ReturnGasAmsterdam(txRegular, txState, st.gasUsed()); err != nil {

View file

@ -139,13 +139,21 @@ func (c *Contract) UseGas(cost GasCosts, logger *tracing.Hooks, reason tracing.G
return true return true
} }
// RefundGas refunds gas to the contract. gasUsed carries the child frame's // RefundGas refunds gas to the contract.
// accumulated gas usage metrics (EIP-8037), incorporated on both success and error.
func (c *Contract) RefundGas(err error, initialRegularGasUsed uint64, gas GasBudget, gasUsed GasUsed, logger *tracing.Hooks, reason tracing.GasChangeReason) { func (c *Contract) RefundGas(err error, initialRegularGasUsed uint64, gas GasBudget, gasUsed GasUsed, logger *tracing.Hooks, reason tracing.GasChangeReason) {
// If the preceding call errored, return the state gas // If the preceding call errored, return the child's state-gas reservoir
// to the parent call // and any net state-gas consumption to the parent. A negative
// gasUsed.StateGas (an unabsorbed SSTORE 0→x→0 refund) is an inflation
// to undo: the matching state mutation was reverted with the child, so
// the refund must not leak back to the parent.
if err != nil { if err != nil {
gas.StateGas += gasUsed.StateGas if gasUsed.StateGas >= 0 {
gas.StateGas += uint64(gasUsed.StateGas)
} else if undo := uint64(-gasUsed.StateGas); gas.StateGas >= undo {
gas.StateGas -= undo
} else {
gas.StateGas = 0
}
gasUsed.StateGas = 0 gasUsed.StateGas = 0
} }
if gas.RegularGas == 0 && gas.StateGas == 0 && gasUsed.StateGas == 0 && gasUsed.RegularGas == 0 { if gas.RegularGas == 0 && gas.StateGas == 0 && gasUsed.StateGas == 0 && gasUsed.RegularGas == 0 {
@ -164,11 +172,7 @@ func (c *Contract) RefundGas(err error, initialRegularGasUsed uint64, gas GasBud
func (c *Contract) RefundCreateStateGas(refund uint64) { func (c *Contract) RefundCreateStateGas(refund uint64) {
if refund > 0 { if refund > 0 {
c.Gas.StateGas += refund c.Gas.StateGas += refund
if c.GasUsed.StateGas >= refund { c.GasUsed.StateGas -= int64(refund)
c.GasUsed.StateGas -= refund
} else {
c.GasUsed.StateGas = 0
}
} }
} }

View file

@ -702,11 +702,7 @@ func gasSStore8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
// refund counter, which is capped at gas_used/5. // refund counter, which is capped at gas_used/5.
stateRefund := params.StorageCreationSize * evm.Context.CostPerGasByte stateRefund := params.StorageCreationSize * evm.Context.CostPerGasByte
contract.Gas.StateGas += stateRefund contract.Gas.StateGas += stateRefund
if contract.GasUsed.StateGas >= stateRefund { contract.GasUsed.StateGas -= int64(stateRefund)
contract.GasUsed.StateGas -= stateRefund
} else {
contract.GasUsed.StateGas = 0
}
// Regular portion of the refund still goes through the refund counter. // Regular portion of the refund still goes through the refund counter.
evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929) evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929)
} else { // reset to original existing slot (2.2.2.2) } else { // reset to original existing slot (2.2.2.2)

View file

@ -18,11 +18,16 @@ package vm
import "fmt" import "fmt"
type GasUsed = GasCosts // GasUsed is the per-frame accumulator for gas consumption.
// StateGas is signed because of 0 -> X -> 0 SSTORE refunds.
type GasUsed struct {
RegularGas uint64
StateGas int64
}
func (g *GasUsed) Add(costs GasCosts) { func (g *GasUsed) Add(costs GasCosts) {
g.RegularGas += costs.RegularGas g.RegularGas += costs.RegularGas
g.StateGas += costs.StateGas g.StateGas += int64(costs.StateGas)
} }
// GasCosts denotes a vector of gas costs in the // GasCosts denotes a vector of gas costs in the
@ -66,11 +71,9 @@ func (g GasBudget) Used(initial GasBudget) uint64 {
return (initial.RegularGas + initial.StateGas) - (g.RegularGas + g.StateGas) return (initial.RegularGas + initial.StateGas) - (g.RegularGas + g.StateGas)
} }
// Exhaust sets all remaining gas to zero, preserving the initial amount // Exhaust burns the remaining regular gas on exceptional halt.
// for usage tracking.
func (g *GasBudget) Exhaust() { func (g *GasBudget) Exhaust() {
g.RegularGas = 0 g.RegularGas = 0
g.StateGas = 0
} }
func (g *GasBudget) Copy() GasBudget { func (g *GasBudget) Copy() GasBudget {