mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-24 23:46:17 +00:00
Claude fixes for Glam-6
- Misc 8037 fixes
This commit is contained in:
parent
dd073df1cd
commit
0b699f5791
4 changed files with 97 additions and 31 deletions
|
|
@ -745,6 +745,13 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
// Execute the transaction's creation.
|
||||
ret, _, result, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining.ForwardAll(), value)
|
||||
st.gasRemaining.Absorb(result)
|
||||
// EIP-8037: a successful creation to a pre-existing (alive) leaf creates
|
||||
// no new account, so refund the intrinsic NEW_ACCOUNT state gas to the
|
||||
// reservoir (fork.py: refunded when created_target_alive). The failure
|
||||
// case is handled by the vmerr branch below.
|
||||
if rules.IsAmsterdam && vmerr == nil && st.evm.CreateTargetWasAlive() {
|
||||
st.gasRemaining.RefundState(params.AccountCreationSize * st.evm.Context.CostPerStateByte)
|
||||
}
|
||||
} else {
|
||||
// Increment the nonce for the next transaction.
|
||||
st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1, tracing.NonceChangeEoACall)
|
||||
|
|
@ -930,13 +937,13 @@ func (st *stateTransition) settleGas(rules params.Rules, floorDataGas uint64) (g
|
|||
}
|
||||
|
||||
if rules.IsAmsterdam {
|
||||
// EIP-7623/7976: the calldata floor applies to the block-level regular
|
||||
// gas dimension as well, mirroring its effect on the receipt gas. The
|
||||
// spec accumulates max(tx_regular_gas, calldata_floor) into
|
||||
// block_gas_used, so the block must never count fewer regular units
|
||||
// than the floor the sender was charged.
|
||||
blockRegularGas := max(txRegularGas, floorDataGas)
|
||||
if err = st.gp.ChargeGasAmsterdam(blockRegularGas, txStateGas, gasUsed); err != nil {
|
||||
// EIP-7778: the block-level gas accounting uses the gross regular gas
|
||||
// (tx_gas_used_before_refund - tx_state_gas) and ignores both the
|
||||
// EIP-3529 refund and the EIP-7623/7976 calldata floor. The floor and
|
||||
// refund only affect the receipt scalar (tx_gas_used) and the sender's
|
||||
// ETH refund, not what the block charges (fork.py: block_gas_used +=
|
||||
// tx_regular_gas).
|
||||
if err = st.gp.ChargeGasAmsterdam(txRegularGas, txStateGas, gasUsed); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
} else {
|
||||
|
|
@ -998,7 +1005,7 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
|
|||
// - the delegation-indicator portion (AuthorizationCreationSize × CPSB) is
|
||||
// refunded when this auth writes no new indicator bytes (the authority is
|
||||
// already delegated, or the auth clears the delegation).
|
||||
func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.SetCodeAuthorization) error {
|
||||
func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.SetCodeAuthorization, preDelegated map[common.Address]bool) error {
|
||||
authority, err := st.validateAuthorization(auth)
|
||||
if err != nil {
|
||||
if rules.IsAmsterdam {
|
||||
|
|
@ -1018,24 +1025,39 @@ func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.Se
|
|||
st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas)
|
||||
}
|
||||
} else {
|
||||
// EIP-8037 (spec apply_authorization): refund the per-auth intrinsic
|
||||
// state charge for state that does not actually get newly created.
|
||||
// EIP-8037/8038 (spec set_delegation): refund the per-auth intrinsic
|
||||
// state charge for state that is not actually newly created.
|
||||
//
|
||||
// - NEW_ACCOUNT is refunded when the authority account already exists
|
||||
// (account_exists), since no new account is created.
|
||||
// delegated_now reflects prior authorizations applied this tx; the
|
||||
// pre-transaction delegation is captured on first touch of the
|
||||
// authority.
|
||||
delegatedNow := curDelegated
|
||||
delegatedBeforeTx, seen := preDelegated[authority]
|
||||
if !seen {
|
||||
delegatedBeforeTx = curDelegated
|
||||
preDelegated[authority] = delegatedBeforeTx
|
||||
}
|
||||
// - NEW_ACCOUNT (+ worst-case ACCOUNT_WRITE regular) is refunded when
|
||||
// the authority account leaf already 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
|
||||
// (code_hash != EMPTY, i.e. curDelegated) or this auth clears the
|
||||
// delegation (auth.address == 0). Exactly one refund per auth.
|
||||
if curDelegated || auth.Address == (common.Address{}) {
|
||||
st.gasRemaining.RefundState(params.AuthorizationCreationSize * st.evm.Context.CostPerStateByte)
|
||||
// - AUTH_BASE refill, mirroring set_delegation:
|
||||
authBase := params.AuthorizationCreationSize * st.evm.Context.CostPerStateByte
|
||||
if auth.Address == (common.Address{}) {
|
||||
// Clearing: refund AUTH_BASE; refund a second time when removing a
|
||||
// delegation that was created earlier in this same transaction
|
||||
// (delegated now but not before the tx).
|
||||
st.gasRemaining.RefundState(authBase)
|
||||
if delegatedNow && !delegatedBeforeTx {
|
||||
st.gasRemaining.RefundState(authBase)
|
||||
}
|
||||
} else if delegatedNow || delegatedBeforeTx {
|
||||
// Setting: refund AUTH_BASE when no new indicator bytes are written
|
||||
// (the authority already carries a delegation now or pre-tx).
|
||||
st.gasRemaining.RefundState(authBase)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1058,8 +1080,14 @@ func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.Se
|
|||
|
||||
// applyAuthorizations applies an EIP-7702 code delegation to the state.
|
||||
func (st *stateTransition) applyAuthorizations(rules params.Rules, auths []types.SetCodeAuthorization) {
|
||||
// preDelegated records each authority's delegation state in the
|
||||
// pre-transaction state, captured on the first authorization that touches
|
||||
// it. EIP-8037 distinguishes a delegation that existed before the
|
||||
// transaction (delegated_before_tx) from one created earlier in the same
|
||||
// transaction (delegated_now) when refilling AUTH_BASE.
|
||||
preDelegated := make(map[common.Address]bool)
|
||||
for _, auth := range auths {
|
||||
st.applyAuthorization(rules, &auth)
|
||||
st.applyAuthorization(rules, &auth, preDelegated)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,13 @@ type EVM struct {
|
|||
// order when the sub-call fails (spec generic_call credit_state_gas_refund).
|
||||
callNewAccountChargedTemp bool
|
||||
|
||||
// createTargetAliveTemp records, for the most recent successful create()
|
||||
// frame, whether the target account leaf was already alive (non-empty)
|
||||
// before the create. opCreate/opCreate2 read it to refund the EIP-8037
|
||||
// NEW_ACCOUNT state gas on a successful create to a pre-existing leaf
|
||||
// (spec create_message: refund when target_alive).
|
||||
createTargetAliveTemp bool
|
||||
|
||||
// precompiles holds the precompiled contracts for the current epoch
|
||||
precompiles map[common.Address]PrecompiledContract
|
||||
|
||||
|
|
@ -491,6 +498,13 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
|||
return ret, exitGas, err
|
||||
}
|
||||
|
||||
// CreateTargetWasAlive reports whether the most recent successful create()
|
||||
// frame targeted an already-alive (non-empty) account leaf. Used by the
|
||||
// transaction-level creation path to apply the EIP-8037 NEW_ACCOUNT refund.
|
||||
func (evm *EVM) CreateTargetWasAlive() bool {
|
||||
return evm.createTargetAliveTemp
|
||||
}
|
||||
|
||||
// create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, result GasBudget, err error) {
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
|
|
@ -552,6 +566,15 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
// address collision while regular gas is burnt.
|
||||
return nil, common.Address{}, halt, ErrContractAddressCollision
|
||||
}
|
||||
// EIP-8037: record whether the target leaf was already alive (non-empty)
|
||||
// before the create. The collision check above already accessed the
|
||||
// account, so this read adds nothing new to the block access list. A
|
||||
// successful create to an already-alive leaf creates no new account, so
|
||||
// opCreate/opCreate2 refunds the NEW_ACCOUNT charge. Captured here (rather
|
||||
// than eagerly in the opcode) so early-failure paths that never reach the
|
||||
// target — depth, insufficient balance — do not record a spurious access.
|
||||
targetAlive := !evm.StateDB.Empty(address)
|
||||
|
||||
// Create a new account on the state only if the object was not present.
|
||||
// It might be possible the contract code is deployed to a pre-existent
|
||||
// account with non-zero balance.
|
||||
|
|
@ -613,7 +636,10 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
return ret, address, exit, err
|
||||
}
|
||||
// Either success, or pre-Homestead ErrCodeStoreOutOfGas (gas preserved).
|
||||
// Both packaged as a success-form GasBudget.
|
||||
// Both packaged as a success-form GasBudget. Record target aliveness for
|
||||
// the EIP-8037 NEW_ACCOUNT refund (set here, after any nested creates ran,
|
||||
// so it reflects this frame's target rather than a deeper one).
|
||||
evm.createTargetAliveTemp = targetAlive
|
||||
return ret, address, contract.Gas.ExitSuccess(), err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -293,4 +293,9 @@ func (g *GasBudget) Absorb(child GasBudget) {
|
|||
g.UsedRegularGas += child.UsedRegularGas
|
||||
g.StateGas = child.StateGas
|
||||
g.UsedStateGas += child.UsedStateGas
|
||||
// A successful child propagates its spilled state gas to the parent so a
|
||||
// later parent halt burns it (spec incorporate_child_on_success). On revert
|
||||
// or halt the child's leftover SpilledStateGas is already zero (the exit
|
||||
// form refilled it), so this is a no-op there.
|
||||
g.SpilledStateGas += child.SpilledStateGas
|
||||
}
|
||||
|
|
|
|||
|
|
@ -663,6 +663,9 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
|
||||
child := scope.Contract.forwardGas(forward, evm.Config.Tracer, tracing.GasChangeCallContractCreation)
|
||||
res, addr, result, suberr := evm.Create(scope.Contract.Address(), input, child, &value)
|
||||
// EIP-8037: a successful create to an already-alive target leaf creates no
|
||||
// new account; create() records that in createTargetAliveTemp.
|
||||
targetWasAlive := evm.chainRules.IsAmsterdam && suberr == nil && evm.createTargetAliveTemp
|
||||
// Push item on the stack based on the returned error. If the ruleset is
|
||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||
// rule) and treat as an error, if the ruleset is frontier we must
|
||||
|
|
@ -679,10 +682,10 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
// Refund the leftover gas back to current frame
|
||||
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
// EIP-8037: no account was created on any failure path, so refund the
|
||||
// account-creation state gas charged before the opcode ran (gasCreateEip8037)
|
||||
// in LIFO order (regular gas up to the spilled amount, then the reservoir).
|
||||
if evm.chainRules.IsAmsterdam && suberr != nil {
|
||||
// EIP-8037: refund the account-creation state gas charged before the opcode
|
||||
// ran (gasCreateEip8037) in LIFO order when no new account leaf is created:
|
||||
// any failure path, or a success where the target leaf already existed.
|
||||
if evm.chainRules.IsAmsterdam && (suberr != nil || targetWasAlive) {
|
||||
scope.Contract.Gas.CreditStateRefund(params.AccountCreationSize * evm.Context.CostPerStateByte)
|
||||
}
|
||||
|
||||
|
|
@ -707,8 +710,12 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
|
||||
// reuse size int for stackvalue
|
||||
stackvalue := size
|
||||
|
||||
child := scope.Contract.forwardGas(forward, evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
|
||||
res, addr, result, suberr := evm.Create2(scope.Contract.Address(), input, child, &endowment, &salt)
|
||||
// EIP-8037: a successful create to an already-alive target leaf creates no
|
||||
// new account; create() records that in createTargetAliveTemp.
|
||||
targetWasAlive := evm.chainRules.IsAmsterdam && suberr == nil && evm.createTargetAliveTemp
|
||||
// Push item on the stack based on the returned error.
|
||||
if suberr != nil {
|
||||
stackvalue.Clear()
|
||||
|
|
@ -720,10 +727,10 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
// Refund the leftover gas back to current frame
|
||||
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
// EIP-8037: no account was created on any failure path, so refund the
|
||||
// account-creation state gas charged before the opcode ran (gasCreate2Eip8037)
|
||||
// in LIFO order (regular gas up to the spilled amount, then the reservoir).
|
||||
if evm.chainRules.IsAmsterdam && suberr != nil {
|
||||
// EIP-8037: refund the account-creation state gas charged before the opcode
|
||||
// ran (gasCreate2Eip8037) in LIFO order when no new account leaf is created:
|
||||
// any failure path, or a success where the target leaf already existed.
|
||||
if evm.chainRules.IsAmsterdam && (suberr != nil || targetWasAlive) {
|
||||
scope.Contract.Gas.CreditStateRefund(params.AccountCreationSize * evm.Context.CostPerStateByte)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue