Skip to content

Commit

Permalink
Update EIP-6493: Define PooledTransaction wrapper for gossip
Browse files Browse the repository at this point in the history
Merged by EIP-Bot.
  • Loading branch information
etan-status authored Aug 30, 2023
1 parent 6a23776 commit 6b3e816
Showing 1 changed file with 67 additions and 8 deletions.
75 changes: 67 additions & 8 deletions EIPS/eip-6493.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ status: Draft
type: Standards Track
category: Core
created: 2023-02-24
requires: 155, 191, 1559, 2718, 2930, 4844, 7495
requires: 155, 191, 1559, 2718, 2930, 4844, 5793, 7495
---

## Abstract
Expand Down Expand Up @@ -46,8 +46,8 @@ The values `0x00` and `0x04` are marked as reserved [EIP-2718](./eip-2718.md) tr

| Name | Value | Description |
| - | - | - |
| (n/a) | `None` | Untyped [`LegacyTransaction`](./eip-2718.md#transactions) |
| `TRANSACTION_TYPE_LEGACY` | `TransactionType(0x00)` | Untyped [`LegacyTransaction`](./eip-2718.md#transactions) with [chain ID](./eip-155.md) |
| (n/a) | `None` | Untyped [`LegacyTransaction`](./eip-2718.md#transactions) ('Homestead' scheme) |
| `TRANSACTION_TYPE_LEGACY` | `TransactionType(0x00)` | Untyped [`LegacyTransaction`](./eip-2718.md#transactions) ([EIP-155 scheme](./eip-155.md)) |
| `TRANSACTION_TYPE_EIP2930` | `TransactionType(0x01)` | [EIP-2930](./eip-2930.md#definitions) transaction |
| `TRANSACTION_TYPE_EIP1559` | `TransactionType(0x02)` | [EIP-1559](./eip-1559.md#specification) transaction |
| `TRANSACTION_TYPE_EIP4844` | `TransactionType(0x03)` | [EIP-4844](./eip-4844.md#parameters) transaction |
Expand All @@ -63,11 +63,16 @@ Definitions from existing specifications that are used throughout this document
| - | - |
| [`Hash32`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/beacon-chain.md#custom-types) | `Bytes32` |
| [`ExecutionAddress`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/bellatrix/beacon-chain.md#custom-types) | `Bytes20` |
| [`KZGCommitment`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/polynomial-commitments.md#custom-types) | `Bytes48` |
| [`KZGProof`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/polynomial-commitments.md#custom-types) | `Bytes48` |
| [`Blob`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/polynomial-commitments.md#custom-types) | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]` |
| [`VersionedHash`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/beacon-chain.md#custom-types) | `Bytes32` |

| Name | Value |
| - | - |
| [`BYTES_PER_LOGS_BLOOM`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/bellatrix/beacon-chain.md#execution) | `uint64(2**8)` (= 256) |
| [`BYTES_PER_FIELD_ELEMENT`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/polynomial-commitments.md#constants) | `uint64(32)` |
| [`FIELD_ELEMENTS_PER_BLOB`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/polynomial-commitments.md#blob) | `uint64(4096)` |
| [`MAX_BLOB_COMMITMENTS_PER_BLOCK`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/beacon-chain.md#execution) | `uint64(2**12)` (= 4,096) |

### SSZ `SignedTransaction` container
Expand Down Expand Up @@ -193,7 +198,7 @@ def compute_ssz_tx_hash(tx: SignedTransaction) -> Hash32:

### Transaction validation

As part of validating a `SignedTransaction`, the `from` address MUST be checked for consistency with the `ecdsa_signature`.
As part of `SignedTransaction` validation, the `from` address MUST be checked for consistency with the `ecdsa_signature`.

```python
def ecdsa_pack_signature(y_parity: bool,
Expand Down Expand Up @@ -235,6 +240,31 @@ def validate_transaction(tx: SignedTransaction,

See [EIP assets](../assets/eip-6493/tx_hashes.py) for a definition of `compute_sig_hash` that takes the various transaction types into account.

### SSZ `PooledTransaction` container

During transaction gossip responses ([`PooledTransactions`](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md#pooledtransactions-0x0a)), each `SignedTransaction` is wrapped into a `PooledTransaction`. The definition uses the `PartialContainer[T, N]` SSZ type and `Optional[E]` as defined in [EIP-7495](./eip-7495.md).

| Name | Value | Description |
| - | - | - |
| `MAX_POOLED_TRANSACTION_FIELDS` | `uint64(2**3)` (= 8) | Maximum number of fields to which `PooledTransaction` can ever grow in the future |

```python
class BlobPayload(Container):
blob: Blob
kzg_commitment: KZGCommitment
kzg_proof: KZGProof

@dataclass
class PooledTransactionPayload:
tx: SignedTransaction
blob_payloads: Optional[List[BlobPayload, MAX_BLOB_COMMITMENTS_PER_BLOCK]]

class PooledTransaction(PartialContainer[PooledTransactionPayload, MAX_POOLED_TRANSACTION_FIELDS]):
pass
```

The same additional validation constraints as defined in [EIP-4844](./eip-4844.md) apply to transactions that define `tx.payload.blob_versioned_hashes` or `blob_payloads`.

### SSZ `Receipt` container

All SSZ receipts are represented as a single, normalized SSZ container. The definition uses the `PartialContainer[T, N]` SSZ type and `Optional[E]` as defined in [EIP-7495](./eip-7495.md).
Expand Down Expand Up @@ -276,6 +306,29 @@ Such changes [do not affect](./eip-7495.md) how existing receipts serialize, mer

![Receipt merkleization](../assets/eip-6493/receipt.png)

### Networking

When exchanging transactions and receipts via the [Ethereum Wire Protocol](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md), the following [EIP-2718](./eip-2718.md) compatible envelopes are used:

- `SignedTransaction`: `TRANSACTION_TYPE_SSZ || snappyFramed(ssz(SignedTransaction))`
- `PooledTransaction`: `TRANSACTION_TYPE_SSZ || snappyFramed(ssz(PooledTransaction))`
- `Receipt`: `TRANSACTION_TYPE_SSZ || snappyFramed(ssz(Receipt))`

Objects are encoded using `SSZ` and compressed using the Snappy framing format, matching the encoding of consensus objects as defined in the [consensus networking specification](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/p2p-interface.md#ssz-snappy-encoding-strategy). As part of the encoding, the uncompressed object length is emited; the recommended limit to enforce per object is [`MAX_CHUNK_SIZE`](https://github.com/ethereum/consensus-specs/blob/e3a939e439d6c05356c9c29c5cd347384180bc01/specs/phase0/p2p-interface.md#configuration) bytes.

Implementations SHALL continue to support accepting RLP transactions into their transaction pool. However, such transactions MUST be converted to SSZ for inclusion into an `ExecutionPayload`. See [EIP assets](../assets/eip-6493/convert.py) for a reference implementation to convert from RLP to SSZ, as well as corresponding [test cases](../assets/eip-6493/convert_tests.py). The original `sig_hash` and `tx_hash` are retained throughout the conversion process.

### Transaction gossip announcements

The semantics of the [`types` element](./eip-5793.md) in transaction gossip announcements ([`NewPooledTransactionHashes`](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md#newpooledtransactionhashes-0x08)) is changed to match `ssz(PooledTransaction.active_fields())`:

| `types` | Description |
| - | - |
| `0x00` | Untyped [`LegacyTransaction`](./eip-2718.md#transactions) ('Homestead' scheme, or [EIP-155 scheme](./eip-155.md)) |
| `0x01` | [EIP-2930](./eip-2930.md) transaction, or basic SSZ `PooledTransaction` without any additional auxiliary payloads |
| `0x02` | [EIP-1559](./eip-1559.md) transaction |
| `0x03` | [EIP-4844](./eip-4844.md) transaction, or SSZ `PooledTransaction` with `blob_payloads` |

## Rationale

### Why SSZ transactions?
Expand All @@ -286,15 +339,15 @@ Such changes [do not affect](./eip-7495.md) how existing receipts serialize, mer

3. **Better for smart contracts:** Smart contracts that validate transactions or receipts benefit from the ability to prove individual chunks of a transaction. Gas fees may be lower, and it becomes possible to process transactions and receipts that do not fully fit into calldata.

4. **Smaller data size:** SSZ objects are typically compressed using Snappy framed compression. Transaction `input` and `access_list` fields and receipt `logs_bloom` and `logs` fields often contain a lot of zero bytes and benefit from this compression. Snappy framed compression allows sending sequences of transactions and receipts without having to recompress, and is designed to be computationally inexpensive.
4. **Smaller data size:** SSZ objects are typically compressed using Snappy framed compression. Transaction `input` and `access_list` fields as well as receipt `logs_bloom` and `logs` fields often contain a lot of zero bytes and benefit from this compression. Snappy framed compression allows sending sequences of transactions and receipts without having to recompress, and is designed to be computationally inexpensive.

### Why include the `from` address in transactions?

For transactions converted from RLP, the `sig_hash` is computed from its original RLP representation. To avoid requiring API clients to implement the original RLP encoding and keccak hashing, the `from` address is included as part of the `SignedTransaction`.

Note that this also eliminates the need for secp256k1 public key recovery when serving JSON-RPC API requests, as the `from` address is already known.

Furthermore, this allows early rejecting transactions that do not pay enough gas, as the `from` account balance can be checked without the computationally expensive `ecrecover`.
Furthermore, this allows early rejecting transactions with sender accounts that do not have sufficient balance, as the `from` account balance can be checked without the computationally expensive `ecrecover`.

### Why include the `contract_address` in receipts?

Expand All @@ -314,6 +367,14 @@ All SSZ transactions (including future ones) share the single [EIP-2718](./eip-2

This also reduces combinatorial explosion; for example, the `access_list` property could be made optional for all SSZ transactions without having to double the number of defined transaction types.

### Why redefine `types` for `NewPooledTransactionHashes`?

The `types` element as introduced in eth/68 via [EIP-5793](./eip-5793.md) allows the receiving node better control over the data it fetches from the peer and allows throttling the download of specific types.

Current implementations primarily use `types` to distinguish type `0x03` blob transactions from basic type `0x00`, `0x01` and `0x02` transactions. However, all SSZ `SignedTransaction` use type `0x04` (`TRANSACTION_TYPE_SSZ`), eliminating this optimization potential.

To restore the optimization potential, `types` is redefined to indicate instead what auxiliary payloads are present in the `PooledTransaction`: SSZ blob transactions will share type `0x03` with RLP blob transactions, while basic SSZ transactions will be assigned type `0x01`, which is currently also used for a basic RLP transaction type. Therefore, implementations will not require changes to distinguish blob transactions from basic transactions.

### Why change from `cumulative_gas_used` to `gas_used` in receipts?

[EIP-658](./eip-658.md) replaced the intermediate post-state `root` from receipts with a boolean `status` code. Replacing `cumulative_gas_used` with `gas_used` likewise replaces the final stateful field with a stateless one, unlocking future optimization potential as transaction receipts operating on distinct state no longer depend on their order. Furthermore, API clients no longer need to fetch information from multiple receipts if they want to validate the `gas_used` of an individual transaction.
Expand All @@ -326,8 +387,6 @@ Existing RLP transactions can be converted to SSZ transactions. Their original `

Existing RLP receipts can be converted to SSZ receipts. The full sequence of accompanying transactions must be known to fill-in the new `contract_address` field. Note that because JSON-RPC exposes the `contract_address`, implementations are already required to know the transaction before queries for receipts can be served.

See [EIP assets](../assets/eip-6493/convert.py) for a reference implementation to convert from RLP to SSZ, as well as corresponding [test cases](../assets/eip-6493/convert_tests.py).

## Test Cases

TBD
Expand Down

0 comments on commit 6b3e816

Please sign in to comment.