diff --git a/core/vm/eips.go b/core/vm/eips.go index 33af8fd4fd..d7239f46a5 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -43,6 +43,7 @@ var activators = map[int]func(*JumpTable){ 7939: enable7939, 8024: enable8024, 7843: enable7843, + 8037: enable8037, } // EnableEIP enables the given EIP on the config. @@ -590,3 +591,9 @@ func enable7843(jt *JumpTable) { maxStack: maxStack(0, 1), } } + +// enable8037 applies EIP-8037: State Creation Gas Cost Increase +func enable8037(jt *JumpTable) { + jt[SLOAD].constantGas = params.SloadGasEIP2200 + jt[SSTORE].dynamicGas = gasSStoreEIP8037 +} diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 046311f9cc..db47d86254 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -226,6 +226,52 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m return GasCosts{RegularGas: params.SloadGasEIP2200}, nil // dirty update (2.2) } +// EIP-8037 constants. EIP-8037 only diverges from EIP-2200 on slots whose +// tx-original is zero AND on writes that cross the zero/non-zero boundary +// (i.e. a state creation or its in-tx undo). Everything else stays on the +// EIP-2200 schedule. +const ( + stateBytesPerSlotEIP8037 = 64 // bytes attributed to one slot's state + costPerStateByteEIP8037 = 1157 // gas per state-creation byte + sstoreBaseGasEIP8037 = 2900 // regular gas baseline for the EIP-8037 transitions + stateGasEIP8037 = stateBytesPerSlotEIP8037 * costPerStateByteEIP8037 +) + +// gasSStoreEIP8037 prices SSTORE under EIP-8037. +// +// Two specific (original, current, value) shapes get the new pricing: +// - O == 0, C == 0, V != 0 — creating fresh state in this tx. +// Charge stateGasEIP8037 of state gas and sstoreBaseGasEIP8037 of regular gas. +// - O == 0, C != 0, V == 0 — undoing the in-tx creation. +// Refund stateGasEIP8037 of state gas (negative StateGas in the cost +// vector) and pay sstoreBaseGasEIP8037 of regular gas. +// +// Every other shape — including O != 0 of any kind, and O == 0 cases that +// don't cross zero — defers to gasSStoreEIP2200 unchanged. +func gasSStoreEIP8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + if evm.readOnly { + return GasCosts{}, ErrWriteProtection + } + if contract.Gas.RegularGas <= params.SstoreSentryGasEIP2200 { + return GasCosts{}, errors.New("not enough gas for reentrancy sentry") + } + var ( + zero = common.Hash{} + y, x = stack.back(1), stack.back(0) + current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), x.Bytes32()) + value = common.Hash(y.Bytes32()) + ) + if original == zero { + switch { + case current == zero && value != zero: // creation + return GasCosts{RegularGas: sstoreBaseGasEIP8037, StateGas: stateGasEIP8037}, nil + case current != zero && value == zero: // undo creation + return GasCosts{RegularGas: sstoreBaseGasEIP8037, StateGas: -stateGasEIP8037}, nil + } + } + return gasSStoreEIP2200(evm, contract, stack, mem, memorySize) +} + func makeGasLog(n uint64) gasFunc { return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { requestedSize, overflow := stack.back(1).Uint64WithOverflow() diff --git a/core/vm/gascosts.go b/core/vm/gascosts.go index cc90c54798..6f18eac18b 100644 --- a/core/vm/gascosts.go +++ b/core/vm/gascosts.go @@ -18,17 +18,16 @@ package vm import "fmt" -// GasCosts denotes a vector of gas costs in the -// multidimensional metering paradigm. It represents the cost -// charged by an individual operation. +// GasCosts denotes a vector of gas costs in the multidimensional metering +// paradigm. It represents the cost charged by an individual operation. +// +// StateGas is signed so an operation can express a state-gas refund +// (negative cost) — e.g. an SSTORE that undoes an in-tx state creation. +// Such a refund flows back into the StateGas reservoir of the GasBudget, +// not into RegularGas. type GasCosts struct { RegularGas uint64 - StateGas uint64 -} - -// Sum returns the total gas (regular + state). -func (g GasCosts) Sum() uint64 { - return g.RegularGas + g.StateGas + StateGas int64 } // String returns a visual representation of the gas vector. diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 82fc43ec13..ce46672b12 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -97,6 +97,7 @@ func newAmsterdamInstructionSet() JumpTable { instructionSet := newOsakaInstructionSet() enable7843(&instructionSet) // EIP-7843 (SLOTNUM opcode) enable8024(&instructionSet) // EIP-8024 (Backward compatible SWAPN, DUPN, EXCHANGE) + enable8037(&instructionSet) // EIP-8037 (State Creation Gas Cost Increase) return validate(instructionSet) }