mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
core: polish auth refund
This commit is contained in:
parent
bf69a15de6
commit
22bfedc4b3
1 changed files with 35 additions and 35 deletions
|
|
@ -909,10 +909,9 @@ func (st *stateTransition) applyAuthorizations(rules params.Rules, auths []types
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Under EIP-8037 each authority can be billed at most one
|
// Under EIP-8037 each authority can be billed at most one
|
||||||
// AuthorizationCreationSize. applyAuthorization records authorities it
|
// AuthorizationCreationSize per tx. applyAuthorization records the
|
||||||
// has billed; we reconcile after the loop by refunding any creation that
|
// authority that bills the per-tx auth-base creation, and refunds it on
|
||||||
// was billed but whose final delegation state in this tx ended up empty
|
// the spot if a later clearing authorization in the same tx undoes it.
|
||||||
// (e.g., 0→a→0).
|
|
||||||
var billed map[common.Address]struct{}
|
var billed map[common.Address]struct{}
|
||||||
if rules.IsAmsterdam {
|
if rules.IsAmsterdam {
|
||||||
billed = make(map[common.Address]struct{})
|
billed = make(map[common.Address]struct{})
|
||||||
|
|
@ -921,23 +920,16 @@ func (st *stateTransition) applyAuthorizations(rules params.Rules, auths []types
|
||||||
// Errors are ignored — invalid authorizations are simply skipped.
|
// Errors are ignored — invalid authorizations are simply skipped.
|
||||||
st.applyAuthorization(rules, &auth, billed)
|
st.applyAuthorization(rules, &auth, billed)
|
||||||
}
|
}
|
||||||
// End-of-loop reconciliation: a billed creation whose authority is no
|
|
||||||
// longer delegated wrote zero net bytes to disk, so the auth-base
|
|
||||||
// intrinsic state gas should not be retained.
|
|
||||||
for authority := range billed {
|
|
||||||
if _, isDelegated := types.ParseDelegation(st.state.GetCode(authority)); !isDelegated {
|
|
||||||
st.gasRemaining.RefundState(params.AuthorizationCreationSize * st.evm.Context.CostPerStateByte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyAuthorization applies an EIP-7702 code delegation to the state.
|
// applyAuthorization applies an EIP-7702 code delegation to the state.
|
||||||
//
|
//
|
||||||
// authBilledCreations, when non-nil, tracks the set of authorities for which
|
// authBilledCreations, when non-nil, tracks the set of authorities for which
|
||||||
// this tx has been billed one AuthorizationCreationSize charge (the per-
|
// this tx has been billed one AuthorizationCreationSize charge (the per-
|
||||||
// authority "first creation" budget). The caller is expected to do an
|
// authority "first creation" budget). A subsequent clearing authorization
|
||||||
// end-of-loop pass over this set and refund any entry whose final delegation
|
// (auth.Address == 0) for an authority in this set refunds the prior bill
|
||||||
// state ended up empty.
|
// and removes the entry, since the net delegation bytes written by the
|
||||||
|
// chain are zero.
|
||||||
func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.SetCodeAuthorization, authBilledCreations map[common.Address]struct{}) error {
|
func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.SetCodeAuthorization, authBilledCreations map[common.Address]struct{}) error {
|
||||||
authority, err := st.validateAuthorization(auth)
|
authority, err := st.validateAuthorization(auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -955,35 +947,43 @@ func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.Se
|
||||||
}
|
}
|
||||||
prevDelegation, isDelegated := types.ParseDelegation(st.state.GetCode(authority))
|
prevDelegation, isDelegated := types.ParseDelegation(st.state.GetCode(authority))
|
||||||
if rules.IsAmsterdam {
|
if rules.IsAmsterdam {
|
||||||
// EIP-8037: refund the auth-base state gas unless this auth is the
|
// EIP-8037: reconcile the per-authority auth-base creation budget.
|
||||||
// first one in this tx to write delegation bytes to an authority
|
//
|
||||||
// whose committed code was empty. Refund when ANY of:
|
// Refill the auth-base for the current authorization if ANY of:
|
||||||
//
|
//
|
||||||
// - the authority was already delegated at the start of the tx
|
// - the authority was already delegated at the start of the tx
|
||||||
// (the 23 bytes are already accounted for in committed state,
|
// (the 23 bytes are already accounted for in committed state),
|
||||||
// and any auth against it just re-writes them);
|
|
||||||
//
|
//
|
||||||
// - the auth is no-op / clearing (auth.Address == 0) — no bytes
|
// - a prior auth in this tx has already billed the auth-base for
|
||||||
// are written in this step at all;
|
// this authority (per-tx per-authority creation budget is 1),
|
||||||
//
|
//
|
||||||
// - we have already billed a creation for this authority in
|
// - auth.Address == 0
|
||||||
// this tx (per-authority creation budget is 1).
|
// - if it was delegated: no charge
|
||||||
|
// - if it wasn't delegated: no-op
|
||||||
//
|
//
|
||||||
// Modeling it this way mirrors the SSTORE "reset to original"
|
// Otherwise, mark this auth as the one that bills the per-tx
|
||||||
// pattern (EIP-2200 / EIP-3529) and avoids both the undercount in
|
// auth-base creation for this authority.
|
||||||
// a→0→b (committed had delegation, second auth missed the refund)
|
//
|
||||||
// and the overcount in 0→a→0→c (each later auth was previously
|
// In addition, if this is a clearing auth (auth.Address == 0) and a
|
||||||
// billed as a fresh creation). The remaining 0→a→0 case — a
|
// prior auth in this tx already billed the auth-base for this
|
||||||
// creation is billed and then undone within the same auth list —
|
// authority, refund that prior bill and drop the mark: the chain of
|
||||||
// is handled by the caller's end-of-loop adjustment over
|
// auths writes zero net delegation bytes, so the earlier bill is no
|
||||||
// authBilledCreations.
|
// longer justified.
|
||||||
_, committedDelegated := types.ParseDelegation(st.state.GetCommittedCode(authority))
|
var (
|
||||||
_, alreadyBilled := authBilledCreations[authority]
|
clearing = auth.Address == (common.Address{})
|
||||||
if committedDelegated || alreadyBilled || auth.Address == (common.Address{}) {
|
_, committedDelegated = types.ParseDelegation(st.state.GetCommittedCode(authority))
|
||||||
|
_, alreadyBilled = authBilledCreations[authority]
|
||||||
|
)
|
||||||
|
if committedDelegated || alreadyBilled || clearing {
|
||||||
st.gasRemaining.RefundState(params.AuthorizationCreationSize * st.evm.Context.CostPerStateByte)
|
st.gasRemaining.RefundState(params.AuthorizationCreationSize * st.evm.Context.CostPerStateByte)
|
||||||
} else {
|
} else {
|
||||||
authBilledCreations[authority] = struct{}{}
|
authBilledCreations[authority] = struct{}{}
|
||||||
}
|
}
|
||||||
|
// Refund that prior bill and drop the mark
|
||||||
|
if clearing && alreadyBilled {
|
||||||
|
st.gasRemaining.RefundState(params.AuthorizationCreationSize * st.evm.Context.CostPerStateByte)
|
||||||
|
delete(authBilledCreations, authority)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update nonce and account code.
|
// Update nonce and account code.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue