Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update EIP-4844: Rename "data gas" to "blob gas" #7354

Merged
merged 1 commit into from
Jul 24, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 48 additions & 48 deletions EIPS/eip-4844.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ Compared to full data sharding, this EIP has a reduced cap on the number of thes
| `BLOB_COMMITMENT_VERSION_KZG` | `Bytes1(0x01)` |
| `POINT_EVALUATION_PRECOMPILE_ADDRESS` | `Bytes20(0x0A)` |
| `POINT_EVALUATION_PRECOMPILE_GAS` | `50000` |
| `MAX_DATA_GAS_PER_BLOCK` | `786432` |
| `TARGET_DATA_GAS_PER_BLOCK` | `393216` |
| `MIN_DATA_GASPRICE` | `1` |
| `DATA_GASPRICE_UPDATE_FRACTION` | `3338477` |
| `MAX_BLOB_GAS_PER_BLOCK` | `786432` |
| `TARGET_BLOB_GAS_PER_BLOCK` | `393216` |
| `MIN_BLOB_GASPRICE` | `1` |
| `BLOB_GASPRICE_UPDATE_FRACTION` | `3338477` |
| `MAX_VERSIONED_HASHES_LIST_SIZE` | `2**24` |
| `MAX_CALLDATA_SIZE` | `2**24` |
| `MAX_ACCESS_LIST_SIZE` | `2**24` |
| `MAX_ACCESS_LIST_STORAGE_KEYS` | `2**24` |
| `MAX_TX_WRAP_COMMITMENTS` | `2**12` |
| `LIMIT_BLOBS_PER_TX` | `2**12` |
| `DATA_GAS_PER_BLOB` | `2**17` |
| `GAS_PER_BLOB` | `2**17` |
| `HASH_OPCODE_BYTE` | `Bytes1(0x49)` |
| `HASH_OPCODE_GAS` | `3` |

Expand Down Expand Up @@ -104,29 +104,29 @@ def fake_exponential(factor: int, numerator: int, denominator: int) -> int:
We introduce a new [EIP-2718](./eip-2718.md) transaction, "blob transaction", where the `TransactionType` is `BLOB_TX_TYPE` and the `TransactionPayload` is the RLP serialization of the following `TransactionPayloadBody`:

```
[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_data_gas, blob_versioned_hashes, y_parity, r, s]
[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_blob_gas, blob_versioned_hashes, y_parity, r, s]
```

The fields `chain_id`, `nonce`, `max_priority_fee_per_gas`, `max_fee_per_gas`, `gas_limit`, `value`, `data`, and `access_list` follow the same semantics as [EIP-1559](./eip-1559.md).

The field `to` deviates slightly from the semantics with the exception that it MUST NOT be `nil` and therefore must always represent a 20-byte address. This means that blob transactions cannot have the form of a create transaction.

The field `max_fee_per_data_gas` is a `uint256` and the field `blob_versioned_hashes` represents a list of hash outputs from `kzg_to_versioned_hash`.
The field `max_fee_per_blob_gas` is a `uint256` and the field `blob_versioned_hashes` represents a list of hash outputs from `kzg_to_versioned_hash`.

The [EIP-2718](./eip-2718.md) `ReceiptPayload` for this transaction is `rlp([status, cumulative_transaction_gas_used, logs_bloom, logs])`.

#### Signature

The signature values `y_parity`, `r`, and `s` are calculated by constructing a secp256k1 signature over the following digest:

`keccak256(BLOB_TX_TYPE || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_data_gas, blob_versioned_hashes]))`.
`keccak256(BLOB_TX_TYPE || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_blob_gas, blob_versioned_hashes]))`.

### Header extension

The current header encoding is extended with two new 64-bit unsigned integer fields:

- `data_gas_used` is the total amount of data gas consumed by the transactions within the block.
- `excess_data_gas` is a running total of data gas consumed in excess of the target, prior to the block. Blocks with above-target data gas consumption increase this value, blocks with below-target data gas consumption decrease it (bounded at 0).
- `blob_gas_used` is the total amount of blob gas consumed by the transactions within the block.
- `excess_blob_gas` is a running total of blob gas consumed in excess of the target, prior to the block. Blocks with above-target blob gas consumption increase this value, blocks with below-target blob gas consumption decrease it (bounded at 0).

The resulting RLP encoding of the header is therefore:

Expand All @@ -149,44 +149,44 @@ rlp([
0x0000000000000000, # nonce
base_fee_per_gas,
withdrawals_root,
data_gas_used,
excess_data_gas,
blob_gas_used,
excess_blob_gas,
])
```

The value of `excess_data_gas` can be calculated using the parent header.
The value of `excess_blob_gas` can be calculated using the parent header.

```python
def calc_excess_data_gas(parent: Header) -> int:
if parent.excess_data_gas + parent.data_gas_used < TARGET_DATA_GAS_PER_BLOCK:
def calc_excess_blob_gas(parent: Header) -> int:
if parent.excess_blob_gas + parent.blob_gas_used < TARGET_BLOB_GAS_PER_BLOCK:
return 0
else:
return parent.excess_data_gas + parent.data_gas_used - TARGET_DATA_GAS_PER_BLOCK
return parent.excess_blob_gas + parent.blob_gas_used - TARGET_BLOB_GAS_PER_BLOCK
```

For the first post-fork block, both `parent.data_gas_used` and `parent.excess_data_gas` are evaluated as `0`.
For the first post-fork block, both `parent.blob_gas_used` and `parent.excess_blob_gas` are evaluated as `0`.

### Gas accounting

We introduce data gas as a new type of gas. It is independent of normal gas and follows its own targeting rule, similar to EIP-1559.
We use the `excess_data_gas` header field to store persistent data needed to compute the data gas price. For now, only blobs are priced in data gas.
We introduce blob gas as a new type of gas. It is independent of normal gas and follows its own targeting rule, similar to EIP-1559.
We use the `excess_blob_gas` header field to store persistent data needed to compute the blob gas price. For now, only blobs are priced in blob gas.

```python
def calc_data_fee(header: Header, tx: SignedBlobTransaction) -> int:
return get_total_data_gas(tx) * get_data_gasprice(header)
return get_total_blob_gas(tx) * get_blob_gasprice(header)

def get_total_data_gas(tx: SignedBlobTransaction) -> int:
return DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)
def get_total_blob_gas(tx: SignedBlobTransaction) -> int:
return GAS_PER_BLOB * len(tx.blob_versioned_hashes)

def get_data_gasprice(header: Header) -> int:
def get_blob_gasprice(header: Header) -> int:
return fake_exponential(
MIN_DATA_GASPRICE,
header.excess_data_gas,
DATA_GASPRICE_UPDATE_FRACTION
MIN_BLOB_GASPRICE,
header.excess_blob_gas,
BLOB_GASPRICE_UPDATE_FRACTION
)
```

The block validity conditions are modified to include data gas checks (see the [Execution layer validation](#execution-layer-validation) section below).
The block validity conditions are modified to include blob gas checks (see the [Execution layer validation](#execution-layer-validation) section below).

The actual `data_fee` as calculated via `calc_data_fee` is deducted from the sender balance before transaction execution and burned, and is not refunded in case of transaction failure.

Expand Down Expand Up @@ -254,18 +254,18 @@ On the execution layer, the block validity conditions are extended as follows:
def validate_block(block: Block) -> None:
...

# check that the excess data gas was updated correctly
assert block.header.excess_data_gas == calc_excess_data_gas(block.parent.header)
# check that the excess blob gas was updated correctly
assert block.header.excess_blob_gas == calc_excess_blob_gas(block.parent.header)

data_gas_used = 0
blob_gas_used = 0

for tx in block.transactions:
...

# modify the check for sufficient balance
max_total_fee = tx.gas * tx.max_fee_per_gas
if type(tx) is SignedBlobTransaction:
max_total_fee += get_total_data_gas(tx) * tx.max_fee_per_data_gas
max_total_fee += get_total_blob_gas(tx) * tx.max_fee_per_blob_gas
assert signer(tx).balance >= max_total_fee

...
Expand All @@ -279,17 +279,17 @@ def validate_block(block: Block) -> None:
for h in tx.blob_versioned_hashes:
assert h[0] == BLOB_COMMITMENT_VERSION_KZG

# ensure that the user was willing to at least pay the current data gasprice
assert tx.max_fee_per_data_gas >= get_data_gasprice(block.header)
# ensure that the user was willing to at least pay the current blob gasprice
assert tx.max_fee_per_blob_gas >= get_blob_gasprice(block.header)

# keep track of total data gas spent in the block
data_gas_used += get_total_data_gas(tx)
# keep track of total blob gas spent in the block
blob_gas_used += get_total_blob_gas(tx)

# ensure the total data gas spent is at most equal to the limit
assert data_gas_used <= MAX_DATA_GAS_PER_BLOCK
# ensure the total blob gas spent is at most equal to the limit
assert blob_gas_used <= MAX_BLOB_GAS_PER_BLOCK

# ensure data_gas_used matches header
assert block.header.data_gas_used == data_gas_used
# ensure blob_gas_used matches header
assert block.header.blob_gas_used == blob_gas_used

```

Expand Down Expand Up @@ -387,22 +387,22 @@ However, the point evaluation happens inside a finite field, and it is only well

In the interest of not adding another precompile, we return the modulus and the polynomial degree directly from the point evaluation precompile. It can then be used by the caller. It is also "free" in that the caller can just ignore this part of the return value without incurring an extra cost -- systems that remain upgradable for the foreseeable future will likely use this route for now.

### Data gasprice update rule
### Blob gasprice update rule

The data gasprice update rule is intended to approximate the formula `data_gasprice = MIN_DATA_GASPRICE * e**(excess_data_gas / DATA_GASPRICE_UPDATE_FRACTION)`,
where `excess_data_gas` is the total "extra" amount of data gas that the chain has consumed relative to the "targeted" number (`TARGET_DATA_GAS_PER_BLOCK` per block).
Like EIP-1559, it's a self-correcting formula: as the excess goes higher, the `data_gasprice` increases exponentially, reducing usage and eventually forcing the excess back down.
The blob gasprice update rule is intended to approximate the formula `blob_gasprice = MIN_BLOB_GASPRICE * e**(excess_blob_gas / BLOB_GASPRICE_UPDATE_FRACTION)`,
where `excess_blob_gas` is the total "extra" amount of blob gas that the chain has consumed relative to the "targeted" number (`TARGET_BLOB_GAS_PER_BLOCK` per block).
Like EIP-1559, it's a self-correcting formula: as the excess goes higher, the `blob_gasprice` increases exponentially, reducing usage and eventually forcing the excess back down.

The block-by-block behavior is roughly as follows.
If block `N` consumes `X` data gas, then in block `N+1` `excess_data_gas` increases by `X - TARGET_DATA_GAS_PER_BLOCK`,
and so the `data_gasprice` of block `N+1` increases by a factor of `e**((X - TARGET_DATA_GAS_PER_BLOCK) / DATA_GASPRICE_UPDATE_FRACTION)`.
If block `N` consumes `X` blob gas, then in block `N+1` `excess_blob_gas` increases by `X - TARGET_BLOB_GAS_PER_BLOCK`,
and so the `blob_gasprice` of block `N+1` increases by a factor of `e**((X - TARGET_BLOB_GAS_PER_BLOCK) / BLOB_GASPRICE_UPDATE_FRACTION)`.
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.

The parameter `DATA_GASPRICE_UPDATE_FRACTION` controls the maximum rate of change of the blob gas price. It is chosen to target a maximum change rate of `e(TARGET_DATA_GAS_PER_BLOCK / DATA_GASPRICE_UPDATE_FRACTION) ≈ 1.125` per block.
The parameter `BLOB_GASPRICE_UPDATE_FRACTION` controls the maximum rate of change of the blob gas price. It is chosen to target a maximum change rate of `e(TARGET_BLOB_GAS_PER_BLOCK / BLOB_GASPRICE_UPDATE_FRACTION) ≈ 1.125` per block.

### Throughput

The values for `TARGET_DATA_GAS_PER_BLOCK` and `MAX_DATA_GAS_PER_BLOCK` are chosen to correspond to a target of 3 blobs (0.375 MB) and maximum of 6 blobs (0.75 MB) per block. These small initial limits are intended to minimize the strain on the network created by this EIP and are expected to be increased in future upgrades as the network demonstrates reliability under larger blocks.
The values for `TARGET_BLOB_GAS_PER_BLOCK` and `MAX_BLOB_GAS_PER_BLOCK` are chosen to correspond to a target of 3 blobs (0.375 MB) and maximum of 6 blobs (0.75 MB) per block. These small initial limits are intended to minimize the strain on the network created by this EIP and are expected to be increased in future upgrades as the network demonstrates reliability under larger blocks.

## Backwards Compatibility

Expand All @@ -421,7 +421,7 @@ By only broadcasting announcements for blob transactions, receiving nodes will h
allowing them to throttle throughput to an acceptable level.
[EIP-5793](./eip-5793.md) will give further fine-grained control to nodes by extending the `NewPooledTransactionHashes` announcement messages to include the transaction type and size.

In addition, we recommend including a 1.1x data gasprice bump requirement to the mempool transaction replacement rules.
In addition, we recommend including a 1.1x blob gasprice bump requirement to the mempool transaction replacement rules.

## Test Cases

Expand Down
Loading