Claude fixes for Glam-6

- BuilderDeposit/Exit code
- Floor base cost
- 8038 gas costs
This commit is contained in:
Marius van der Wijden 2026-06-24 15:48:16 +02:00
parent 7a1fbe0e85
commit 9c7bd2abe5
5 changed files with 135 additions and 66 deletions

View file

@ -230,12 +230,18 @@ func FloorDataGas(rules params.Rules, data []byte, accessList types.AccessList)
tokenCost = params.TxCostFloorPerToken
}
// The floor cost is anchored to the transaction base cost. EIP-2780
// (Amsterdam) replaces the legacy 21000 base with TX_BASE (12000).
floorBase := params.TxGas
if rules.IsAmsterdam {
floorBase = params.TxBaseCost2780
}
// Check for overflow
if (math.MaxUint64-params.TxGas)/tokenCost < tokens {
if (math.MaxUint64-floorBase)/tokenCost < tokens {
return 0, ErrGasUintOverflow
}
// Minimum gas required for a transaction based on its data tokens (EIP-7623).
return params.TxGas + tokens*tokenCost, nil
return floorBase + tokens*tokenCost, nil
}
// toWordSize returns the ceiled word size required for init code payment calculation.
@ -1015,6 +1021,10 @@ func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.Se
// (account_exists), since no new account is created.
if st.state.Exist(authority) {
st.gasRemaining.RefundState(params.AccountCreationSize * st.evm.Context.CostPerStateByte)
// EIP-8038: the worst-case ACCOUNT_WRITE charged per authorization in
// the intrinsic cost is refunded to the regular refund counter when
// the authority account already exists (no new account is created).
st.state.AddRefund(params.AccountWriteAmsterdam)
}
// - AUTH_BASE is refunded when no new delegation-indicator bytes are
// written: either the authority already carries code/delegation

View file

@ -600,4 +600,21 @@ func enable8037(jt *JumpTable) {
jt[CREATE2].dynamicGas = gasCreate2Eip8037
jt[SELFDESTRUCT].dynamicGas = gasSelfdestruct8037
jt[SSTORE].dynamicGas = gasSStore8037
// EIP-8038: EXTCODESIZE charges an additional warm-access "code reading"
// cost. EXTCODECOPY's extra cost is handled inline in gasExtCodeCopyEIP2929;
// EXTCODESIZE shares gasEip2929AccountCheck with BALANCE/EXTCODEHASH (which
// do not get the extra cost), so it needs a dedicated calculator.
jt[EXTCODESIZE].dynamicGas = gasExtCodeSize8037
}
// gasExtCodeSize8037 is the EXTCODESIZE gas calculator for Amsterdam. It adds
// the EIP-8038 warm-access "code reading" cost on top of the account-access
// cost computed by gasEip2929AccountCheck.
func gasExtCodeSize8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
cost, err := gasEip2929AccountCheck(evm, contract, stack, mem, memorySize)
if err != nil {
return GasCosts{}, err
}
cost.RegularGas += params.WarmStorageReadCostEIP2929
return cost, nil
}

View file

@ -492,6 +492,10 @@ func gasCallIntrinsic(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
var transferGas uint64
if transfersValue && !evm.chainRules.IsEIP4762 {
transferGas = params.CallValueTransferGas
if evm.chainRules.IsAmsterdam {
// EIP-8038: CALL_VALUE = ACCOUNT_WRITE + CALL_STIPEND.
transferGas = params.CallValueTransferAmsterdam
}
}
var overflow bool
if gas, overflow = math.SafeAdd(memoryGas, transferGas); overflow {
@ -546,7 +550,12 @@ func gasCallCodeIntrinsic(evm *EVM, contract *Contract, stack *Stack, mem *Memor
overflow bool
)
if stack.back(2).Sign() != 0 && !evm.chainRules.IsEIP4762 {
gas += params.CallValueTransferGas
transferGas := params.CallValueTransferGas
if evm.chainRules.IsAmsterdam {
// EIP-8038: CALL_VALUE = ACCOUNT_WRITE + CALL_STIPEND.
transferGas = params.CallValueTransferAmsterdam
}
gas += transferGas
}
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
return 0, ErrGasUintOverflow
@ -606,7 +615,7 @@ func gasSelfdestruct8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory
if !evm.StateDB.AddressInAccessList(address) {
// If the caller cannot afford the cost, this change will be rolled back
evm.StateDB.AddAddressToAccessList(address)
gas.RegularGas = params.ColdAccountAccessCostEIP2929
gas.RegularGas = params.ColdAccountAccessAmsterdam
}
// Check we have enough regular gas before we add the address to the BAL
if contract.Gas.RegularGas < gas.RegularGas {
@ -620,78 +629,78 @@ func gasSelfdestruct8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory
// Funding such an account makes it permanent state growth and must be charged.
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
gas.StateGas += params.AccountCreationSize * evm.Context.CostPerStateByte
// EIP-8038: positive balance sent to an empty account also charges the
// regular ACCOUNT_WRITE cost.
gas.RegularGas += params.AccountWriteAmsterdam
}
return gas, nil
}
// gasSStore8037 is the SSTORE gas calculator for Amsterdam (EIP-8037 +
// EIP-8038). It mirrors amsterdam/vm/instructions/storage.py::sstore:
//
// - a cold/warm access cost is always charged (regular);
// - a STORAGE_WRITE cost is charged once, on the first change to the slot in
// the transaction (regular);
// - creating a slot from zero charges STORAGE_SET state gas, refunded to the
// reservoir if the slot is later restored to zero in the same tx;
// - clearing an originally non-zero slot credits/reverses REFUND_STORAGE_CLEAR
// and restoring a changed slot refunds the STORAGE_WRITE, both via the
// (gas_used/5-capped) refund counter.
func gasSStore8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) {
if evm.readOnly {
return GasCosts{}, ErrWriteProtection
}
// If we fail the minimum gas availability invariant, fail (0)
if contract.Gas.RegularGas <= params.SstoreSentryGasEIP2200 {
// Stipend sentry: require strictly more than the call stipend (spec
// check_gas(CALL_STIPEND + 1)).
if contract.Gas.RegularGas <= params.CallStipend {
return GasCosts{}, errors.New("not enough gas for reentrancy sentry")
}
// Gas sentry honoured, do the actual gas calculation based on the stored value
var (
y, x = stack.back(1), stack.peek()
slot = common.Hash(x.Bytes32())
current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot)
newValue = common.Hash(y.Bytes32())
stateSetGas = params.StorageCreationSize * evm.Context.CostPerStateByte
cost GasCosts
)
// Check slot presence in the access list
// Access cost: cold or warm, always charged.
if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent {
cost = GasCosts{RegularGas: params.ColdSloadCostEIP2929}
// If the caller cannot afford the cost, this change will be rolled back
// If the caller cannot afford the cost, this change will be rolled back.
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
cost.RegularGas += params.ColdStorageAccessAmsterdam
} else {
cost.RegularGas += params.WarmStorageReadCostEIP2929
}
value := common.Hash(y.Bytes32())
if current == value { // noop (1)
// EIP 2200 original clause:
// return params.SloadGasEIP2200, nil
return GasCosts{RegularGas: cost.RegularGas + params.WarmStorageReadCostEIP2929}, nil // SLOAD_GAS
// Write cost: charged on the first change to the slot this transaction.
if original == current && current != newValue {
cost.RegularGas += params.StorageWriteAmsterdam
}
if original == current {
if original == (common.Hash{}) { // create slot (2.1.1)
return GasCosts{
RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929,
StateGas: params.StorageCreationSize * evm.Context.CostPerStateByte,
}, nil
// Refund counter (regular).
if current != newValue {
if original != (common.Hash{}) && current != (common.Hash{}) && newValue == (common.Hash{}) {
// Storage cleared for the first time in the transaction.
evm.StateDB.AddRefund(params.SstoreClearsRefundAmsterdam)
}
if value == (common.Hash{}) { // delete slot (2.1.2b)
evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP3529)
if original != (common.Hash{}) && current == (common.Hash{}) {
// A refund issued earlier this tx is reversed.
evm.StateDB.SubRefund(params.SstoreClearsRefundAmsterdam)
}
// EIP-2200 original clause:
// return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2)
return GasCosts{RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929}, nil // write existing slot (2.1.2)
}
if original != (common.Hash{}) {
if current == (common.Hash{}) { // recreate slot (2.2.1.1)
evm.StateDB.SubRefund(params.SstoreClearsScheduleRefundEIP3529)
} else if value == (common.Hash{}) { // delete slot (2.2.1.2)
evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP3529)
if original == newValue {
// Slot restored to its original value: refund the STORAGE_WRITE
// charged on the first-time change earlier this transaction.
evm.StateDB.AddRefund(params.StorageWriteAmsterdam)
}
}
if original == value {
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
// EIP-8037 point (2): refund state gas directly to the reservoir
// at the SSTORE restoration point (0→x→0 in same tx); not to the
// refund counter, which is capped at gas_used/5.
contract.Gas.RefundState(params.StorageCreationSize * evm.Context.CostPerStateByte)
// Regular portion of the refund still goes through the refund counter.
evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929)
} else { // reset to original existing slot (2.2.2.2)
// EIP 2200 Original clause:
// evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
// - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST)
// - SLOAD_GAS redefined as WARM_STORAGE_READ_COST
// Final: (5000 - COLD_SLOAD_COST) - WARM_STORAGE_READ_COST
evm.StateDB.AddRefund((params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.WarmStorageReadCostEIP2929)
}
// State gas (reservoir).
if original == current && current != newValue && original == (common.Hash{}) {
// Slot created from zero: charge STORAGE_SET state gas.
cost.StateGas = stateSetGas
}
// EIP-2200 original clause:
//return params.SloadGasEIP2200, nil // dirty update (2.2)
return GasCosts{RegularGas: cost.RegularGas + params.WarmStorageReadCostEIP2929}, nil // dirty update (2.2)
if current != newValue && original == newValue && original == (common.Hash{}) {
// Slot set then cleared in the same tx: refund the state gas directly
// to the reservoir (not the gas_used/5-capped refund counter).
contract.Gas.RefundState(stateSetGas)
}
return cost, nil
}

View file

@ -106,7 +106,12 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
// If the caller cannot afford the cost, this change will be rolled back
// If he does afford it, we can skip checking the same thing later on, during execution
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
return GasCosts{RegularGas: params.ColdSloadCostEIP2929}, nil
coldCost := params.ColdSloadCostEIP2929
if evm.chainRules.IsAmsterdam {
// EIP-8038: cold storage access raised to 3000.
coldCost = params.ColdStorageAccessAmsterdam
}
return GasCosts{RegularGas: coldCost}, nil
}
return GasCosts{RegularGas: params.WarmStorageReadCostEIP2929}, nil
}
@ -125,16 +130,24 @@ func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memo
gas := gasCost.RegularGas
addr := common.Address(stack.peek().Bytes20())
// Check slot presence in the access list
coldCost := params.ColdAccountAccessCostEIP2929
// EIP-8038: in Amsterdam cold account access is 3000 and EXTCODECOPY also
// charges an extra warm-access "code reading" cost.
var codeReadingCost uint64
if evm.chainRules.IsAmsterdam {
coldCost = params.ColdAccountAccessAmsterdam
codeReadingCost = params.WarmStorageReadCostEIP2929
}
if !evm.StateDB.AddressInAccessList(addr) {
evm.StateDB.AddAddressToAccessList(addr)
var overflow bool
// We charge (cold-warm), since 'warm' is already charged as constantGas
if gas, overflow = math.SafeAdd(gas, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929); overflow {
if gas, overflow = math.SafeAdd(gas, coldCost-params.WarmStorageReadCostEIP2929); overflow {
return GasCosts{}, ErrGasUintOverflow
}
return GasCosts{RegularGas: gas}, nil
return GasCosts{RegularGas: gas + codeReadingCost}, nil
}
return GasCosts{RegularGas: gas}, nil
return GasCosts{RegularGas: gas + codeReadingCost}, nil
}
// gasEip2929AccountCheck checks whether the first stack item (as address) is present in the access list.
@ -150,8 +163,13 @@ func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Mem
if !evm.StateDB.AddressInAccessList(addr) {
// If the caller cannot afford the cost, this change will be rolled back
evm.StateDB.AddAddressToAccessList(addr)
coldCost := params.ColdAccountAccessCostEIP2929
if evm.chainRules.IsAmsterdam {
// EIP-8038: cold account access raised to 3000.
coldCost = params.ColdAccountAccessAmsterdam
}
// The warm storage read cost is already charged as constantGas
return GasCosts{RegularGas: params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929}, nil
return GasCosts{RegularGas: coldCost - params.WarmStorageReadCostEIP2929}, nil
}
return GasCosts{}, nil
}
@ -282,7 +300,12 @@ func makeCallVariantGasCallEIP7702(intrinsicFunc intrinsicGasFunc) gasFunc {
eip2929Cost uint64
eip7702Cost uint64
addr = common.Address(stack.back(1).Bytes20())
// EIP-8038: cold account access raised to 3000 in Amsterdam.
coldCost = params.ColdAccountAccessCostEIP2929
)
if evm.chainRules.IsAmsterdam {
coldCost = params.ColdAccountAccessAmsterdam
}
// Perform EIP-2929 checks (stateless), checking address presence
// in the accessList and charge the cold access accordingly.
if !evm.StateDB.AddressInAccessList(addr) {
@ -291,7 +314,7 @@ func makeCallVariantGasCallEIP7702(intrinsicFunc intrinsicGasFunc) gasFunc {
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form
// of a constant cost, so the cost to charge for cold access, if any,
// is Cold - Warm
eip2929Cost = params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
eip2929Cost = coldCost - params.WarmStorageReadCostEIP2929
// Charge the remaining difference here already, to correctly calculate
// available gas for call
@ -322,7 +345,7 @@ func makeCallVariantGasCallEIP7702(intrinsicFunc intrinsicGasFunc) gasFunc {
eip7702Cost = params.WarmStorageReadCostEIP2929
} else {
evm.StateDB.AddAddressToAccessList(target)
eip7702Cost = params.ColdAccountAccessCostEIP2929
eip7702Cost = coldCost
}
if !contract.chargeRegular(eip7702Cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
return GasCosts{}, ErrOutOfGas

View file

@ -88,7 +88,7 @@ const (
LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
Create2Gas uint64 = 32000 // Once per CREATE2 operation
CreateGasAmsterdam uint64 = 9000 // Regular gas portion of CREATE in Amsterdam (EIP-8037); state gas is charged separately.
CreateGasAmsterdam uint64 = 11000 // Regular gas portion of CREATE in Amsterdam (EIP-8038: ACCOUNT_WRITE + COLD_STORAGE_ACCESS); state gas is charged separately.
CreateNGasEip4762 uint64 = 1000 // Once per CREATEn operations post-verkle
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation.
MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
@ -101,7 +101,7 @@ const (
TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list
TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list
TxAuthTupleGas uint64 = 12500 // Per auth tuple code specified in EIP-7702
TxAuthTupleRegularGas uint64 = 7500 // Per auth tuple regular gas specified in EIP-8037
TxAuthTupleRegularGas uint64 = 15816 // Per auth tuple regular gas in Amsterdam (EIP-8038: ACCOUNT_WRITE 8000 + REGULAR_PER_AUTH_BASE_COST 7816)
// EIP-2780: resource-based intrinsic transaction gas.
TxBaseCost2780 uint64 = 12000
@ -110,6 +110,16 @@ const (
TxValueCost2780 uint64 = 4244
TransferLogCost2780 uint64 = 1756
// EIP-8038: state-access gas cost update (the Amsterdam repricing of the
// regular-gas portion of state-touching operations). These supersede the
// EIP-2929 cold-access costs for the Amsterdam fork only.
ColdAccountAccessAmsterdam uint64 = 3000 // COLD_ACCOUNT_ACCESS
ColdStorageAccessAmsterdam uint64 = 3000 // COLD_STORAGE_ACCESS
StorageWriteAmsterdam uint64 = 10000 // STORAGE_WRITE (regular write cost, charged on first change)
AccountWriteAmsterdam uint64 = 8000 // ACCOUNT_WRITE
CallValueTransferAmsterdam uint64 = 10300 // CALL_VALUE = ACCOUNT_WRITE + CALL_STIPEND
SstoreClearsRefundAmsterdam uint64 = 12480 // REFUND_STORAGE_CLEAR = (STORAGE_WRITE + COLD_STORAGE_ACCESS) * 4800 / 5000
// These have been changed during the course of the chain
CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction.
CallGasEIP150 uint64 = 700 // Static portion of gas for CALL-derivates after EIP 150 (Tangerine)
@ -249,10 +259,10 @@ var (
ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd")
// EIP-8282 - Builder Execution Requests
BuilderDepositAddress = common.HexToAddress("0x0000000000000000000000000000000000007732")
BuilderDepositCode = common.FromHex("") // TODO (MariusVanDerWijden) add code
BuilderExitAddress = common.HexToAddress("0x0000000000000000000000000000000000007733")
BuilderExitCode = common.FromHex("") // TODO (MariusVanDerWijden) add code
BuilderDepositAddress = common.HexToAddress("0x0000884d2AA32eAa155F59A2f24eFa73D9008282")
BuilderDepositCode = common.FromHex("0x3373fffffffffffffffffffffffffffffffffffffffe146101065760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461023457600182026001905f5b5f82111560695781019083028483029004916001019190604e565b90939004925050503660b814608957366102345734610234575f5260205ff35b8034106102345760383567ffffffffffffffff1680633b9aca001161023457633b9aca00029034031061023457600154600101600155600354806006026004015f358155600101602035815560010160403581556001016060358155600101608035815560010160a035905560b85f5f3760b85fa0600101600355005b600354600254808203806101001161011d57506101005b5f5b8181146101c3578281016006026004018160b8028154815260200181600101548152602001816002015480825260401c67ffffffffffffffff16816010018160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360200181600301548152602001816004015481526020019060050154905260010161011f565b91018092146101d557906002556101e0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561020d57505f5b6001546020828201116102225750505f610228565b01602090035b5f555f60015560b8025ff35b5f5ffd")
BuilderExitAddress = common.HexToAddress("0x000014574A74c805590AFF9499fc7A690f008282")
BuilderExitCode = common.FromHex("0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461018857600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603014608857366101885734610188575f5260205ff35b341061018857600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260305f60143760445fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101175782810160030260040181604402815460601b8152601401816001015481526020019060020154905260010160e1565b91018092146101295790600255610134565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561016157505f5b6001546002828201116101765750505f61017c565b01600290035b5f555f6001556044025ff35b5f5ffd")
)
// System log events.