diff --git a/EIPS/eip-4844.md b/EIPS/eip-4844.md index c0af580d875d9e..d81f9d4f18e97e 100644 --- a/EIPS/eip-4844.md +++ b/EIPS/eip-4844.md @@ -39,8 +39,6 @@ Compared to full data sharding, this EIP has a reduced cap on the number of thes | Constant | Value | | - | - | -| `SYSTEM_STATE_ADDRESS` | `0x000.....0100`| -| `TOTAL_BLOB_TXS_STORAGE_SLOT` | `0` | | `BLOB_TX_TYPE` | `Bytes1(0x05)` | | `FIELD_ELEMENTS_PER_BLOB` | `4096` | | `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | @@ -234,6 +232,46 @@ def get_origin(tx: SignedBlobTransaction) -> Address: return ecrecover(tx_hash(tx), int(sig.y_parity)+27, sig.r, sig.s) ``` +### Header extension + +The current header encoding is extended with a new 256-bit unsigned integer field `excess_blobs`. This is the running +total of excess blobs included on chain since this EIP was activated. If the total number of blobs is below the +average, `excess_blobs` is capped at zero. + +The resulting RLP encoding of the header is therefore: + +``` +rlp([ + parent_hash, + ommers_hash, + coinbase, + state_root, + tx_root, + receipt_root, + bloom, + difficulty, + number, + gas_limit, + gas_used, + time, + extra, + mix_digest, + nonce, + base_fee, + excess_blobs +]) +``` + +The value of `excess_blobs` can be calculated using the parent header and number of blobs in the block. + +```python +def calc_excess_blobs(parent: Header, new_blobs: int) -> int: + if parent.excess_blobs + new_blobs < TARGET_BLOBS_PER_BLOCK: + return 0 + else: + return parent.excess_blobs + new_blobs - TARGET_BLOBS_PER_BLOCK +``` + ### Beacon chain validation On the consensus-layer the blobs are now referenced, but not fully encoded, in the beacon block body. @@ -290,8 +328,8 @@ For early draft implementations, we simply change `get_blob_gas(pre_state)` to a ### Gas price update rule (Full version) We propose a simple independent EIP-1559-style targeting rule to compute the gas cost of the transaction. -We use the `TOTAL_BLOB_TXS_STORAGE_SLOT` storage slot of the `SYSTEM_STATE_ADDRESS` address -to store persistent data needed to compute the cost. +We use the `blobs` header field to store persistent data needed to compute the cost. + Note that unlike existing transaction types, the gas cost is dependent on the pre-state of the block. ```python @@ -307,42 +345,10 @@ def get_intrinsic_gas(tx: SignedBlobTransaction, pre_state: ExecState) -> int: intrinsic_gas += len(tx.message.blob_versioned_hashes) * get_blob_gas(pre_state) return intrinsic_gas -def get_blob_gas(pre_state: ExecState) -> int: - blocks_since_start = get_current_block(pre_state) - FORK_BLKNUM - targeted_total = blocks_since_start * TARGET_BLOB_TXS_PER_BLOCK - actual_total = read_storage( - pre_state, - SYSTEM_STATE_ADDRESS, - TOTAL_BLOB_TXS_STORAGE_SLOT - ) - if actual_total < targeted_total: - return 0 - else: - return fake_exponential( - actual_total - targeted_total, - GASPRICE_UPDATE_FRACTION_PER_BLOB - ) -``` - -We update at the end of a block, as follows: - -```python -def update_blob_gas(state: ExecState, blob_txs_in_block: int): - current_total = read_storage( - state, - SYSTEM_STATE_ADDRESS, - TOTAL_BLOB_TXS_STORAGE_SLOT - ) - # Don't let the new total fall behind the targeted total to avoid - # accumulating a long period of very low fees - blocks_since_start = get_current_block(pre_state) - FORK_BLKNUM - targeted_total = blocks_since_start * TARGET_BLOB_TXS_PER_BLOCK - new_total = max(current_total + blob_txs_in_block, targeted_total) - write_storage( - state, - SYSTEM_STATE_ADDRESS, - TOTAL_BLOB_TXS_STORAGE_SLOT, - new_total +def get_blob_gas(header: Header) -> int: + return fake_exponential( + header.excess_blobs, + GASPRICE_UPDATE_FRACTION_PER_BLOB ) ``` @@ -465,7 +471,6 @@ This EIP also sets the stage for longer-term protocol cleanups: and paves the precedent that all new transaction types should be SSZ * It defines `TransactionNetworkPayload` to separate network and block encodings of a transaction type * Its (cleaner) gas price update rule could be applied to the primary basefee. - It also starts the trend toward using the state to store system state instead of having "implied state" such as historical blocks and hashes. ### How rollups would function @@ -494,12 +499,12 @@ sequencers would simply have to switch over to using a new transaction type at t ### Blob gasprice update rule The blob gasprice update rule is intended to approximate the formula `blob_gas = 2**(excess_blobs / GASPRICE_UPDATE_FRACTION_PER_BLOB)`, -where `excess_blobs` is the total "extra" number of blobs that the chain has accepted relative to the "targeted" number (`TARGET_BLOB_TXS_PER_BLOCK` per block). +where `excess_blobs` is the total "extra" number of blobs that the chain has accepted relative to the "targeted" number (`TARGET_BLOBS_PER_BLOCK` per block). Like EIP-1559, it's a self-correcting formula: as the excess goes higher, the `blob_gas` increases exponentially, reducing usage and eventually forcing the excess back down. The block-by-block behavior is roughly as follows. -If in block `N`, `blob_gas = G1`, and block `N` has `X` blobs, then in block `N+1`, `excess_blobs` increases by `X - TARGET_BLOB_TXS_PER_BLOCK`, -and so the `blob_gas` of block `N+1` increases by a factor of `2**((X - TARGET_BLOB_TXS_PER_BLOCK) / GASPRICE_UPDATE_FRACTION_PER_BLOB)`. +If in block `N`, `blob_gas = G1`, and block `N` has `X` blobs, then in block `N+1`, `excess_blobs` increases by `X - TARGET_BLOBS_PER_BLOCK`, +and so the `blob_gas` of block `N+1` increases by a factor of `2**((X - TARGET_BLOBS_PER_BLOCK) / GASPRICE_UPDATE_FRACTION_PER_BLOB)`. Hence, it has a similar effect to the existing EIP-1559, but is more "stable" in the sense that it responds in the same way to the same total usage regardless of how it's distributed. ## Backwards Compatibility