diff --git a/EIPS/eip-2780.md b/EIPS/eip-2780.md index 36c409e70e4117..aaafb9f1ec8415 100644 --- a/EIPS/eip-2780.md +++ b/EIPS/eip-2780.md @@ -13,9 +13,9 @@ requires: 2718, 2929, 2930, 6780, 7623, 7702, 7708, 7928, 8037, 8038 ## Abstract -This EIP decomposes the flat `21,000` intrinsic transaction cost into explicit primitives, each priced to match the resources a transaction actually consumes. The costs of plain ETH transfers and contract creation transactions remain equal, while ETH transfers to new accounts and [7702](./eip-7702.md)-related transactions +This EIP decomposes the flat `21,000` intrinsic transaction cost into explicit primitives, each priced to match the resources a transaction actually consumes. A plain ETH transfer to an existing account remains at `21,000` execution gas, and contract-creation transactions cost the same whether or not they carry value. Transactions that create new accounts or interact with [EIP-7702](./eip-7702.md) pay the additional runtime costs they incur. -In addition, the new primitives are split into intrinsic gas and runtime gas. **Intrinsic gas** is the state-independent cost of including the transaction in a block and is the sole input to the transaction-validity check. **Runtime gas** covers the state-dependent charges, such as new account creation and delegation resolution. Runtime gas is charged as the first frame is entered, metered in same way as inside the frame. Running out of gas in runtime does not invalidate the transaction. Instead, the transaction is included, execution is skipped, and all state changes are reverted, as for any out-of-gas halt inside a frame. +In addition, the new primitives are split into intrinsic gas and runtime gas. **Intrinsic gas** is the state-independent cost of including the transaction in a block and is the sole input to the transaction-validity check. **Runtime gas** covers the state-dependent charges, such as new account creation and delegation resolution. Runtime gas is charged before the first frame is entered and is metered in the same way as gas inside the frame. Running out of runtime gas does not invalidate the transaction. Instead, the transaction is included, execution is skipped, and the pre-execution state changes are reverted. This EIP does not change calldata or access-list metering. @@ -69,7 +69,7 @@ A transaction's intrinsic base cost is decomposed into the following explicit pr - otherwise, charge `TX_VALUE_COST` in execution gas. - each [EIP-7702](./eip-7702.md) authorization is charged `EXECUTION_PER_AUTH_BASE_COST` in execution gas. -The recipient touch and the authority access (inside `EXECUTION_PER_AUTH_BASE_COST`) are charged at the cold rate every time, even if the account would be warm (for example, via an access list) keeping intrinsic gas computable without any state read. = +The recipient touch and the authority access (inside `EXECUTION_PER_AUTH_BASE_COST`) are charged at the cold rate every time, even if the account would be warm (for example, via an access list), keeping intrinsic gas computable without any state read. These charges replace the legacy contract-creation transaction charges and EIP-7702's flat `PER_EMPTY_ACCOUNT_COST × authorization_list_length` intrinsic charge. @@ -77,7 +77,7 @@ Calldata and access-list metering remain unchanged. ### Runtime gas costs -Once the transaction passes the intrinsic gas check, the state-dependent gas costs (i.e., runtime costs) are applied. The runtime charges happen in a distinct window — the pre-execution phase — after the transaction is already deemed valid but before the first EVM frame is entered. This phase includes the following action, by order: +Once the transaction passes the intrinsic gas check, the state-dependent gas costs (i.e., runtime costs) are applied. The runtime charges happen in a distinct window — the pre-execution phase — after the transaction is already deemed valid but before the first EVM frame is entered. This phase includes the following actions, in order: 1. The available gas is split into `gas_left` and `state_gas_reservoir`, and all the gas accounting counters are initialized, per [EIP-8037](./eip-8037.md); 2. [EIP-7702](./eip-7702.md) authorizations are processed; @@ -88,7 +88,7 @@ Like every charge in this EIP, each runtime charge is split into execution gas a Running out of gas during these runtime charges does **not** invalidate the transaction. Validity is decided solely by the intrinsic gas check. -If the transaction goes out-of-gas in this pre-execution phase, the sender pays for all gas consumed, and all state changes are reverted, including any [EIP-7702](./eip-7702.md) delegations. By contrast, if the transaction goes out-of-gas after entering the first EVM frame, the delegations applied during the pre-execution phase stay in place, per [EIP-7702](./eip-7702.md); the state gas that paid for them — each authority's account-creation and delegation-indicator bytes — therefore stays consumed, since that state persists beyond the frame. Runtime state charges whose state is instead rolled back with the frame (for example, a contract-creation transaction's new-account charge; see below) are refilled in LIFO order per [EIP-8037](./eip-8037.md), and execution-gas runtime charges (such as a delegation-target access) remain consumed. +If the transaction goes out-of-gas in this pre-execution phase, the sender pays for all gas consumed, and all pre-execution state changes are reverted, including any [EIP-7702](./eip-7702.md) delegations. The included transaction still increments the sender's nonce and pays its gas fees. By contrast, if the transaction goes out-of-gas after entering the first EVM frame, the delegations applied during the pre-execution phase stay in place, per [EIP-7702](./eip-7702.md); the state gas that paid for them — each authority's account-creation and delegation-indicator bytes — therefore stays consumed, since that state persists beyond the frame. Runtime state charges whose state is instead rolled back with the frame (for example, a contract-creation transaction's new-account charge; see below) are refilled in LIFO order per [EIP-8037](./eip-8037.md), and execution-gas runtime charges (such as a delegation-target access) remain consumed. If a contract-creation transaction's initcode reverts, the transaction remains valid and any state gas charged at runtime is refilled in last-in, first-out (LIFO) order, per [EIP-8037](./eip-8037.md): the portion the charge drew from `gas_left` is credited back to `gas_left`, and only the remainder returns to the `state_gas_reservoir`. @@ -103,22 +103,22 @@ While processing each valid authorization, the following charges are applied **a - is `tx.sender`, covered by `TX_BASE_COST`; - was written by a preceding valid authorization; - is `tx.to` of a value-bearing transaction, covered by `TX_VALUE_COST`; -- if the authorization writes the 23-byte delegation indicator into a previously empty slot (net-new delegation bytes), charge `STATE_BYTES_PER_AUTH_BASE × CPSB` in state gas. +- if the authorization sets a non-zero delegation target, the authority had no delegation indicator at transaction start, and no earlier authorization set one for that authority in this transaction, charge `STATE_BYTES_PER_AUTH_BASE × CPSB` in state gas. Clearing an indicator does not refund this charge or make a later set chargeable again. An indicator present at transaction start can be cleared and re-set without paying this charge. -For each authorization, after the gas charges of that authorization are processed, the authority is added to `accessed_addresses`, per [EIP-7702](./eip-7702.md). +Authorization validation and warming retain the ordering in [EIP-7702](./eip-7702.md): check the chain ID and nonce bound, recover the authority, add it to `accessed_addresses`, and then check its code and current nonce. An authorization skipped because of the latter checks still warms the recovered authority; one rejected before recovery does not. The state-dependent charges above apply only after validation succeeds, before applying the authorization. #### Account creation and access charges -If the transaction is not a self-transfer nor a contract creation, then the following charges are applied: +If the transaction is not a contract creation, then the following charges are applied: -- if the recipient is non-existent and `tx.value > 0`, charge `STATE_BYTES_PER_NEW_ACCOUNT × CPSB` in state gas; +- if the recipient is non-existent and `tx.value > 0`, charge `STATE_BYTES_PER_NEW_ACCOUNT × CPSB` in state gas (never applies to a self-transfer, whose recipient is the already-existing sender); - if the recipient is an [EIP-7702](./eip-7702.md) delegated account, additionally charge the delegation-target access in execution gas: `COLD_ACCOUNT_ACCESS` if cold, `WARM_ACCESS` if warm. For a contract-creation transaction, if the deployment address does not already exist, per the existence rule of [EIP-8037](./eip-8037.md), charge `STATE_BYTES_PER_NEW_ACCOUNT × CPSB` in state gas. ### Transaction reference cases -Costs are split between the intrinsic phase and the runtime phase, each in execution gas and state gas, per [EIP-8037](./eip-8037.md). "execution" denotes contract execution charged at the standard schedule; it, and every runtime charge, is drawn from the gas passed into the first frame, so that frame is entered with the gas remaining after the runtime execution and state charges. The recipient touch is charged at the cold rate at the intrinsic phase; the only runtime account access is the delegation-target load, shown at the cold rate — a target warmed beforehand pays `WARM_ACCESS` rather than `COLD_ACCOUNT_ACCESS`. Create rows assume the deployment target does not already exist; a pre-existing target pays no new-account state charge. The intrinsic + runtime totals match the legacy headline numbers. +Costs are split between the intrinsic phase and the runtime phase, each in execution gas and state gas, per [EIP-8037](./eip-8037.md). "execution" denotes contract execution charged at the standard schedule; it, and every runtime charge, is drawn from the gas passed into the first frame, so that frame is entered with the gas remaining after the runtime execution and state charges. The recipient touch is charged at the cold rate at the intrinsic phase; the only runtime account access is the delegation-target load, shown at the cold rate — a target warmed beforehand pays `WARM_ACCESS` rather than `COLD_ACCOUNT_ACCESS`. Create rows assume the deployment target does not already exist; a pre-existing target pays no new-account state charge. A plain ETH transfer to an existing EOA remains at the legacy `21,000` execution gas; the other rows show the decomposition for each transaction shape. | Case | Intrinsic (execution / state) | Runtime (execution / state) | Total (execution / state) | | :---- | :---- | :---- | :----: | @@ -139,8 +139,8 @@ Costs are split between the intrinsic phase and the runtime phase, each in execu - **[EIP-2929](./eip-2929.md) (warm/cold accounting).** The sender access folded into `TX_BASE_COST`, the recipient's `COLD_ACCOUNT_ACCESS`, and the authority access inside `EXECUTION_PER_AUTH_BASE_COST` are all charged at the intrinsic phase at fixed cold rates, independent of the account's warm/cold state — an access-list entry for the recipient or an authority does not discount them. The sender, the recipient, and each processed authority are added to `accessed_addresses`, so subsequent execution-level touches are warm. The only runtime account access is the delegation-target load, which follows the standard EIP-2929 warm/cold model: `COLD_ACCOUNT_ACCESS` if cold, `WARM_ACCESS` if warm. The same model governs all execution-level account touches, including internal `CALL`s. - **[EIP-2930](./eip-2930.md) (access lists).** Access lists keep their existing per-entry charges and warming semantics for execution-level touches. Listing the recipient or an authority does not reduce the intrinsic cold-rate charges; it only pre-warms the address for execution. -- **[EIP-7623](./eip-7623.md) (calldata floor).** EIP-7623 floors a transaction's cost at `21,000 + TOTAL_COST_FLOOR_PER_TOKEN × tokens_in_calldata`, where the flat `21,000` is the intrinsic base this EIP decomposes. With this EIP active, that base term is replaced by the transaction's decomposed execution-gas intrinsic — the sum of the execution-gas intrinsic primitives (`TX_BASE_COST + COLD_ACCOUNT_ACCESS + TX_VALUE_COST` for value transfers, `TX_BASE_COST + CREATE_ACCESS` for contract creation) — so the floor and its validity check rest on the same per-transaction base as the rest of intrinsic gas rather than a stale constant. Like the floor, this base is state-independent, so the state-dependent runtime charges (the new-account state-gas charge and the delegation-target access) do not enter it. The calldata schedule itself is unchanged; only the base the floor sits on moves. -- **[EIP-7702](./eip-7702.md) (set EOA code).** `TX_BASE_COST` is unchanged even when the sender temporarily assumes code; clients must not perform a disk code load to classify the sender, since EIP-7702 provides the code inline. When `tx.to` is a delegated account, resolving the delegation loads the target's code, charged `COLD_ACCOUNT_ACCESS` on first touch or warm thereafter, following the standard EIP-2929 `accessed_addresses` model. Setting a delegation (writing the 23-byte pointer) is distinct from resolving one (reading the target's code); the resolution charge is genuine work and is not prepaid by the authorization. Authorization cost itself is decomposed: `EXECUTION_PER_AUTH_BASE_COST` — which already includes the authority's cold access — is charged per authorization at the intrinsic phase, while the state-dependent charges (`STATE_BYTES_PER_NEW_ACCOUNT × CPSB` for a non-existent authority, `ACCOUNT_WRITE` for the first write to the authority within the transaction, and `STATE_BYTES_PER_AUTH_BASE × CPSB` for net-new delegation bytes) are charged at runtime during authorization processing, replacing the worst-case `PER_EMPTY_ACCOUNT_COST` intrinsic charge and refund. +- **[EIP-7623](./eip-7623.md) (calldata floor).** EIP-7623 floors a transaction's cost at `21,000 + TOTAL_COST_FLOOR_PER_TOKEN × tokens_in_calldata`, where the flat `21,000` is the intrinsic base this EIP decomposes. With this EIP active, that base term is replaced by the transaction's decomposed base — `TX_BASE_COST` plus the applicable recipient and value primitives (`COLD_ACCOUNT_ACCESS` and `TX_VALUE_COST` for a value transfer to a different account, or `CREATE_ACCESS` for contract creation). Per-authorization charges and initcode word charges are excluded from this base, so the floor and its validity check rest on the same per-transaction base as the rest of intrinsic gas rather than a stale constant. Like the floor, this base is state-independent, so the state-dependent runtime charges (the new-account state-gas charge and the delegation-target access) do not enter it. The calldata schedule itself is unchanged; only the base the floor sits on moves. +- **[EIP-7702](./eip-7702.md) (set EOA code).** `TX_BASE_COST` is unchanged when the sender is delegated or an authorization changes its delegation. An authorization supplies a delegation target address, not the target's code. Computing the intrinsic charge does not require loading that code; resolving a delegation for execution does. When `tx.to` is a delegated account, resolving the delegation loads the target's code, charged `COLD_ACCOUNT_ACCESS` on first touch or warm thereafter, following the standard EIP-2929 `accessed_addresses` model. Setting a delegation (writing the 23-byte pointer) is distinct from resolving one (reading the target's code); the resolution charge is genuine work and is not prepaid by the authorization. Authorization cost itself is decomposed: `EXECUTION_PER_AUTH_BASE_COST` — which already includes the authority's cold access — is charged per authorization at the intrinsic phase, while the state-dependent charges (`STATE_BYTES_PER_NEW_ACCOUNT × CPSB` for a non-existent authority, `ACCOUNT_WRITE` for the first write to the authority within the transaction, and `STATE_BYTES_PER_AUTH_BASE × CPSB` for net-new delegation bytes) are charged at runtime during authorization processing, replacing the worst-case `PER_EMPTY_ACCOUNT_COST` intrinsic charge and refund. - **[EIP-7708](./eip-7708.md) (ETH transfers emit a log).** Every non-zero-value transfer to a different account emits a transfer log; its cost is folded into `TX_VALUE_COST` alongside the recipient balance write rather than priced as a separate primitive. - **[EIP-7928](./eip-7928.md) (block-level access lists).** `tx.sender` is accessed at the intrinsic phase and `tx.to` at the runtime phase, so both are included in the block-level access list even when the transaction reverts. @@ -188,7 +188,7 @@ Only `tx.data` bytes are metered at the calldata schedule; the envelope RLP (`no ### Self-transfers -A self-transfer (`tx.sender == tx.to`) charges neither the recipient touch nor the value cost: the account is already accessed and written as the sender, and EIP-7708 emits no transfer log when sender and recipient coincide. Only `TX_BASE_COST` applies. +A self-transfer (`tx.sender == tx.to`) charges neither the recipient touch nor the value cost: the account is already accessed and written as the sender, and EIP-7708 emits no transfer log when sender and recipient coincide. Only `TX_BASE_COST` applies to the intrinsic base. If the sender is delegated, the delegation-target access and any delegated execution are still charged at runtime. ### Decomposing authorization cost @@ -200,10 +200,10 @@ This EIP is **not** backward compatible. It is a consensus gas repricing that mu ## Test Cases -Costs are given as intrinsic + runtime, by case: +Costs are given as intrinsic + runtime, by case. These examples omit calldata, access-list, and initcode word charges and, except in case 8, authorization charges; executed code is charged separately. Delegation-target accesses shown at the cold rate cost `WARM_ACCESS` instead when the target is already warm: -1. Self-transfer (`from == to`): `12,000` intrinsic, `0` runtime. -2. Zero-value transaction to any address (existing, empty, or contract): `15,000` intrinsic (`TX_BASE_COST + COLD_ACCOUNT_ACCESS`), `0` runtime, `0` state. A self-target is `12,000`. +1. Self-transfer (`from == to`): `12,000` intrinsic, `0` runtime. If the sender is 7702-delegated, the delegation-target access is additionally charged at runtime, per case 5. +2. Zero-value transaction to a distinct existing or empty EOA: `15,000` intrinsic (`TX_BASE_COST + COLD_ACCOUNT_ACCESS`), `0` runtime, `0` state. A contract recipient additionally pays for execution; a delegated recipient also pays for the delegation-target access. A self-target has a `12,000` intrinsic base, with delegated execution charged as in case 1. 3. Value transfer to an existing EOA: `21,000` intrinsic, `0` runtime, `0` state. 4. Value transfer creating a new account (recipient non-existent): `21,000` intrinsic execution; `STATE_BYTES_PER_NEW_ACCOUNT × CPSB` = `183,600` runtime state. 5. Value transfer to a 7702-delegated account: `21,000` intrinsic + `COLD_ACCOUNT_ACCESS` runtime = `24,000` execution gas plus contract execution. diff --git a/EIPS/eip-8246.md b/EIPS/eip-8246.md index 5e38ab131d2a04..8be64cf6a01350 100644 --- a/EIPS/eip-8246.md +++ b/EIPS/eip-8246.md @@ -69,7 +69,9 @@ For the balance-only accounts created this way, `CREATE2` still may recreate a c For contracts not created in the same transaction in which `SELFDESTRUCT` is executed, the behavior is unchanged from [EIP-6780](./eip-6780.md). -Unlike Mainnet, Optimism-based L2 chains use the burn feature of `SELFDESTRUCT` regularly. These chains will require a separate migration plan. +Unlike Mainnet, some L2 chains use the burn feature of `SELFDESTRUCT` regularly and will require a separate migration plan. + +In the OP Stack, ETH withdrawn to L1 accumulates in the `L2ToL1MessagePasser` predeploy at `0x4200000000000000000000000000000000000016`. It provides a permissionless `burn()` function which destroys that balance by creating a contract whose constructor executes `SELFDESTRUCT` with itself as the beneficiary, so the L2 ETH supply does not inflate. Chains derived from that codebase inherit the dependency unless they modify the predeploy, including those not commonly identified as Optimism-based. Such contracts are deployed with `CREATE`, so the balance-only accounts they leave behind cannot be recreated by the `CREATE2` pattern described above. ## Test Cases @@ -118,6 +120,7 @@ Each of the following test cases should be executed (where physically meaningful 1. `SELFDESTRUCT` behavior modification has a combinatorial effect on a vast number of test scenarios involving multi-call/create contract interactions. This EIP requires significant testing effort. However, many existing test cases for EIP-6780 can be adapted to the new behavior. 2. When a use case relies on the ETH burn happening, the transaction will create dust-like accounts with potentially locked non-zero balance. However, the new account creation gas cost is paid by the transaction, so dust accounts are not a free DoS vector. Only 2 such events have been recorded on Mainnet (Cancun–25M) so far. +3. Preserving the balance leaves a funded account whose nonce, code and storage are cleared, which makes the address a valid `CREATE2` target again (a non-zero balance alone never triggers a creation collision, per [EIP-684](./eip-684.md)). The `(sender, salt, initcode)` of a deployment is public data, so when the `sender` is a permissionless factory anyone can redeploy the account and potentially take the preserved balance. ## Copyright