From f3deac81cfe9806b5d742e37c0178801b73c040f Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Sun, 15 Sep 2024 13:54:34 +0200 Subject: [PATCH] Update EIP-6404: Move to Draft Merged by EIP-Bot. --- EIPS/eip-6404.md | 364 +++++++++++- EIPS/eip-6465.md | 8 +- EIPS/eip-6466.md | 116 +++- EIPS/eip-6493.md | 532 ++---------------- assets/eip-6404/convert.py | 149 +++++ .../{eip-6493 => eip-6404}/convert_tests.py | 73 +-- assets/{eip-6493 => eip-6404}/rlp_types.py | 124 ++-- assets/{eip-6493 => eip-6404}/ssz_types.py | 282 ++++------ assets/{eip-6493 => eip-6404}/transaction.png | Bin assets/eip-6404/tx_hashes.py | 127 +++++ assets/{eip-6493 => eip-6466}/receipt.png | Bin assets/eip-6493/convert.py | 234 -------- assets/eip-6493/tx_hashes.py | 157 ------ 13 files changed, 935 insertions(+), 1231 deletions(-) create mode 100644 assets/eip-6404/convert.py rename assets/{eip-6493 => eip-6404}/convert_tests.py (64%) rename assets/{eip-6493 => eip-6404}/rlp_types.py (61%) rename assets/{eip-6493 => eip-6404}/ssz_types.py (55%) rename assets/{eip-6493 => eip-6404}/transaction.png (100%) create mode 100644 assets/eip-6404/tx_hashes.py rename assets/{eip-6493 => eip-6466}/receipt.png (100%) delete mode 100644 assets/eip-6493/convert.py delete mode 100644 assets/eip-6493/tx_hashes.py diff --git a/EIPS/eip-6404.md b/EIPS/eip-6404.md index c3cd64e1e5fc8..fba1295285a3d 100644 --- a/EIPS/eip-6404.md +++ b/EIPS/eip-6404.md @@ -1,41 +1,332 @@ --- eip: 6404 -title: SSZ Transactions Root -description: Migration of transactions MPT commitment to SSZ +title: SSZ Transactions +description: Migration of RLP transactions to SSZ author: Etan Kissling (@etan-status), Vitalik Buterin (@vbuterin) -discussions-to: https://ethereum-magicians.org/t/eip-6404-ssz-transactions-root/12783 +discussions-to: https://ethereum-magicians.org/t/eip-6404-ssz-transactions/12783 status: Draft type: Standards Track category: Core created: 2023-01-30 -requires: 6493, 7495 +requires: 155, 1559, 2718, 2930, 4844, 5793, 7495 --- ## Abstract -This EIP defines a migration process of existing Merkle-Patricia Trie (MPT) commitments for transactions to [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md). +This EIP defines a migration process of [EIP-2718](./eip-2718.md) Recursive-Length Prefix (RLP) transactions to [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md). ## Motivation -While the consensus `ExecutionPayloadHeader` and the execution block header map to each other conceptually, they are encoded differently. This EIP aims to align the encoding of the `transactions_root`, taking advantage of the more modern SSZ format. This brings several advantages: +RLP transactions have a number of shortcomings: -1. **Transaction inclusion proofs:** Changing the transaction representation to [EIP-6493 `Transaction`](./eip-6493.md) commits to the transaction root hash on-chain, allowing verification of the list of all transaction hashes within a block, and allowing compact transaction inclusion proofs. +1. **Linear hashing:** The signing hash (`sig_hash`) and unique identifier (`tx_hash`) of an RLP transaction are computed by linear keccak256 hashes across its serialization. Even if only partial data is of interest, linear hashes require the full transaction data to be present, including potentially large calldata or access lists. This also applies when computing the `from` address of a transaction based on the `sig_hash`. -2. **Reducing complexity:** The proposed design reduces the number of use cases that require support for Merkle-Patricia Trie (MPT), RLP encoding, keccak hashing, and secp256k1 public key recovery. +2. **Inefficient inclusion proofs:** The Merkle-Patricia Trie (MPT) backing the execution block header's `transactions_root` is constructed from the serialized transactions, internally prepending a prefix to the transaction data before it is keccak256 hashed into the MPT. Due to this prefix, there is no on-chain commitment to the `tx_hash` and inclusion proofs require the full transaction data to be present. -3. **Reducing ambiguity:** The name `transactions_root` is currently used to refer to different roots. While the execution block header refers to a Merkle Patricia Trie (MPT) root, the consensus `ExecutionPayloadHeader` instead refers to an SSZ root. With these changes, `transactions_root` consistently refers to the same SSZ root. +3. **Incompatible representation:** As part of the consensus `ExecutionPayload`, the RLP serialization of transactions is hashed using SSZ merkleization. These SSZ hashes are incompatible with both the `tx_hash` and the MPT `transactions_root`. + +4. **No extensibility:** Transaction types cannot be extended with optional features. Hypothetically, if [EIP-4844](./eip-4844.md) blob transactions existed from the start, new features such as [EIP-2930](./eip-2930.md) access lists and [EIP-1559](./eip-1559.md) priority fees would have required two new transacion types each to extend both the basic and blob transaction types. + +5. **Technical debt:** All client applications and smart contracts handling RLP transactions have to correctly deal with caveats such as `LegacyTransaction` lacking a prefix byte, the inconsistent `chain_id` and `v` / `y_parity` semantics, and the introduction of `max_priority_fee_per_gas` between other fields instead of at the end. As existing transaction types tend to remain valid perpetually, this technical debt builds up over time. + +6. **Inappropriate opaqueness:** The Consensus Layer treats RLP transaction data as opaque, but requires validation of consensus `blob_kzg_commitments` against transaction `blob_versioned_hashes`, resulting in a more complex than necessary engine API. + +This EIP defines a lossless conversion mechanism to normalize transaction representation across both Consensus Layer and Execution Layer while retaining support for processing RLP transaction types. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -### Consensus `ExecutionPayload` changes +### Existing definitions -When building a consensus `ExecutionPayload`, the [`transactions`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/capella/beacon-chain.md#executionpayload) list is now based on the [`Transaction`](./eip-6493.md) SSZ container. [EIP-6493](./eip-6493.md) defines how RLP transactions can be converted to SSZ. +Definitions from existing specifications that are used throughout this document are replicated here for reference. | Name | Value | | - | - | | [`MAX_TRANSACTIONS_PER_PAYLOAD`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/bellatrix/beacon-chain.md#execution) | `uint64(2**20)` (= 1,048,576) | +| [`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) | + +| Name | SSZ equivalent | +| - | - | +| [`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` | +| [`VersionedHash`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/beacon-chain.md#custom-types) | `Bytes32` | +| [`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]` | + +### `ExecutionSignature` container + +Signatures use their native, opaque representation, and are extended with an on-chain commitment to the `from` address. + +| Name | Value | Description | +| - | - | - | +| `ECDSA_SIGNATURE_SIZE` | `32 + 32 + 1` (= 65) | Byte length of an ECDSA (secp256k1) signature | +| `MAX_EXECUTION_SIGNATURE_FIELDS` | `uint64(2**4)` (= 16) | Maximum number of fields to which `ExecutionSignature` can ever grow in the future | + +```python +class ExecutionSignature(StableContainer[MAX_EXECUTION_SIGNATURE_FIELDS]): + from_: Optional[ExecutionAddress] + ecdsa_signature: Optional[ByteVector[ECDSA_SIGNATURE_SIZE]] + +class EcdsaExecutionSignature(Profile[ExecutionSignature]): + from_: ExecutionAddress + ecdsa_signature: ByteVector[ECDSA_SIGNATURE_SIZE] + +def ecdsa_pack_signature(y_parity: bool, + r: uint256, + s: uint256) -> ByteVector[ECDSA_SIGNATURE_SIZE]: + return r.to_bytes(32, 'big') + s.to_bytes(32, 'big') + bytes([0x01 if y_parity else 0x00]) + +def ecdsa_unpack_signature(signature: ByteVector[ECDSA_SIGNATURE_SIZE]) -> tuple[bool, uint256, uint256]: + y_parity = signature[64] != 0 + r = uint256.from_bytes(signature[0:32], 'big') + s = uint256.from_bytes(signature[32:64], 'big') + return (y_parity, r, s) + +def ecdsa_validate_signature(signature: ByteVector[ECDSA_SIGNATURE_SIZE]): + SECP256K1N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 + assert signature[64] in (0, 1) + _, r, s = ecdsa_unpack_signature(signature) + assert 0 < r < SECP256K1N + assert 0 < s <= SECP256K1N // 2 + +def ecdsa_recover_from_address(signature: ByteVector[ECDSA_SIGNATURE_SIZE], + sig_hash: Hash32) -> ExecutionAddress: + ecdsa = ECDSA() + recover_sig = ecdsa.ecdsa_recoverable_deserialize(signature[0:64], signature[64]) + public_key = PublicKey(ecdsa.ecdsa_recover(sig_hash, recover_sig, raw=True)) + uncompressed = public_key.serialize(compressed=False) + return ExecutionAddress(keccak(uncompressed[1:])[12:]) +``` + +### `Transaction` container + +All transactions are represented as a single, normalized SSZ container. The definition uses the `StableContainer[N]` SSZ type and `Optional[T]` as defined in [EIP-7495](./eip-7495.md). + +| Name | Value | Description | +| - | - | - | +| `MAX_FEES_PER_GAS_FIELDS` | `uint64(2**4)` (= 16) | Maximum number of fields to which `FeesPerGas` can ever grow in the future | +| `MAX_CALLDATA_SIZE` | `uint64(2**24)` (= 16,777,216) | Maximum `input` calldata byte length for a transaction | +| `MAX_ACCESS_LIST_STORAGE_KEYS` | `uint64(2**19)` (= 524,288) | Maximum number of storage keys within an access tuple | +| `MAX_ACCESS_LIST_SIZE` | `uint64(2**19)` (= 524,288) | Maximum number of access tuples within an `access_list` | +| `MAX_TRANSACTION_PAYLOAD_FIELDS` | `uint64(2**5)` (= 32) | Maximum number of fields to which `TransactionPayload` can ever grow in the future | + +| Name | SSZ equivalent | Description | +| - | - | - | +| `TransactionType` | `uint8` | [EIP-2718](./eip-2718.md) transaction type, range `[0x00, 0x7F]` | +| `ChainId` | `uint64` | [EIP-155](./eip-155.md) chain ID at time of signature | +| `FeePerGas` | `uint256` | Fee per unit of gas, cannot overflow across an entire block | + +```python +class FeesPerGas(StableContainer[MAX_FEES_PER_GAS_FIELDS]): + regular: Optional[FeePerGas] + + # EIP-4844 + blob: Optional[FeePerGas] + +class AccessTuple(Container): + address: ExecutionAddress + storage_keys: List[Hash32, MAX_ACCESS_LIST_STORAGE_KEYS] + +class TransactionPayload(StableContainer[MAX_TRANSACTION_PAYLOAD_FIELDS]): + # EIP-2718 + type_: Optional[TransactionType] + + # EIP-155 + chain_id: Optional[ChainId] + + nonce: Optional[uint64] + max_fees_per_gas: Optional[FeesPerGas] + gas: Optional[uint64] + to: Optional[ExecutionAddress] + value: Optional[uint256] + input_: Optional[ByteList[MAX_CALLDATA_SIZE]] + + # EIP-2930 + access_list: Optional[List[AccessTuple, MAX_ACCESS_LIST_SIZE]] + + # EIP-1559 + max_priority_fees_per_gas: Optional[FeesPerGas] + + # EIP-4844 + blob_versioned_hashes: Optional[List[VersionedHash, MAX_BLOB_COMMITMENTS_PER_BLOCK]] + +class Transaction(Container): + payload: TransactionPayload + signature: ExecutionSignature +``` + +![Transaction merkleization](../assets/eip-6404/transaction.png) + +### `Transaction` profiles + +[EIP-7495](./eip-7495.md) `Profile` definitions provide type safety for valid transactions. Their original RLP `TransactionType` is retained to enable recovery of their original RLP representation and associated `sig_hash` and `tx_hash` values where necessary. + +```python +class BasicFeesPerGas(Profile[FeesPerGas]): + regular: FeePerGas + +class BlobFeesPerGas(Profile[FeesPerGas]): + regular: FeePerGas + blob: FeePerGas + +class RlpLegacyTransactionPayload(Profile[TransactionPayload]): + type_: TransactionType + chain_id: Optional[ChainId] + nonce: uint64 + max_fees_per_gas: BasicFeesPerGas + gas: uint64 + to: Optional[ExecutionAddress] + value: uint256 + input_: ByteList[MAX_CALLDATA_SIZE] + +class RlpLegacyTransaction(Container): + payload: RlpLegacyTransactionPayload + signature: EcdsaExecutionSignature + +class RlpAccessListTransactionPayload(Profile[TransactionPayload]): + type_: TransactionType + chain_id: ChainId + nonce: uint64 + max_fees_per_gas: BasicFeesPerGas + gas: uint64 + to: Optional[ExecutionAddress] + value: uint256 + input_: ByteList[MAX_CALLDATA_SIZE] + access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] + +class RlpAccessListTransaction(Container): + payload: RlpAccessListTransactionPayload + signature: EcdsaExecutionSignature + +class RlpFeeMarketTransactionPayload(Profile[TransactionPayload]): + type_: TransactionType + chain_id: ChainId + nonce: uint64 + max_fees_per_gas: BasicFeesPerGas + gas: uint64 + to: Optional[ExecutionAddress] + value: uint256 + input_: ByteList[MAX_CALLDATA_SIZE] + access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] + max_priority_fees_per_gas: BasicFeesPerGas + +class RlpFeeMarketTransaction(Container): + payload: RlpFeeMarketTransactionPayload + signature: EcdsaExecutionSignature + +class RlpBlobTransactionPayload(Profile[TransactionPayload]): + type_: TransactionType + chain_id: ChainId + nonce: uint64 + max_fees_per_gas: BlobFeesPerGas + gas: uint64 + to: ExecutionAddress + value: uint256 + input_: ByteList[MAX_CALLDATA_SIZE] + access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] + max_priority_fees_per_gas: BlobFeesPerGas + blob_versioned_hashes: List[VersionedHash, MAX_BLOB_COMMITMENTS_PER_BLOCK] + +class RlpBlobTransaction(Container): + payload: RlpBlobTransactionPayload + signature: EcdsaExecutionSignature +``` + +A helper is provided to identify the the [EIP-7495](./eip-7495.md) `Profile` of a normalized `Transaction`. The type system ensures that fields required by a `Profile` are present and that excluded fields are absent. + +```python +LEGACY_TX_TYPE = TransactionType(0x00) +ACCESS_LIST_TX_TYPE = TransactionType(0x01) +FEE_MARKET_TX_TYPE = TransactionType(0x02) +BLOB_TX_TYPE = TransactionType(0x03) + +def identify_transaction_profile(tx: Transaction) -> Type[Profile]: + if tx.payload.type_ == BLOB_TX_TYPE: + return RlpBlobTransaction + + if tx.payload.type_ == FEE_MARKET_TX_TYPE: + return RlpFeeMarketTransaction + + if tx.payload.type_ == ACCESS_LIST_TX_TYPE: + return RlpAccessListTransaction + + if tx.payload.type_ == LEGACY_TX_TYPE: + return RlpLegacyTransaction + + raise Exception(f'Unsupported transaction: {tx}') +``` + +### Transaction validation + +As part of `Transaction` validation, the `from` address MUST be checked for consistency with the `ecdsa_signature`. See [EIP assets](../assets/eip-6404/tx_hashes.py) for a definition of `compute_sig_hash` that takes the various transaction types into account. + +```python +def validate_tx_from_address(tx): + ecdsa_validate_signature(tx.signature.ecdsa_signature) + assert tx.signature.from_ == ecdsa_recover_from_address( + tx.signature.ecdsa_signature, + compute_sig_hash(tx), + ) +``` + +Additionally, `tx.payload.max_priority_fees_per_gas.blob` MUST be checked to be set to `0` if defined. This limitation ensures feature parity of SSZ transactions with RLP transactions and MAY be relaxed by a future EIP. + +### Execution block header changes + +The [execution block header's `txs-root`](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md#block-encoding-and-validity) is transitioned from MPT to SSZ. + +```python +transactions = List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]( + tx_0, tx_1, tx_2, ...) + +block_header.transactions_root = transactions.hash_tree_root() +``` + +### Engine API + +In the engine API, the structure of the `transactions` field in `ExecutionPayload` versions adopting this EIP is changed from `Array of DATA` to `Array of TransactionV1`. + +`TransactionV1` is defined to map onto the SSZ `Transaction` type, as follows: + +- `payload`: `TransactionPayloadV1` - An `OBJECT` containing the fields of a `TransactionPayloadV1` structure +- `signature`: `ExecutionSignatureV1` - An `OBJECT` containing the fields of a `ExecutionSignatureV1` structure + +`TransactionPayloadV1` is defined to map onto the SSZ `TransactionPayload` `StableContainer`, as follows: + +- `type`: `QUANTITY|null`, 8 Bits or `null` +- `chainId`: `QUANTITY|null`, 64 Bits or `null` +- `nonce`: `QUANTITY|null`, 64 Bits or `null` +- `maxFeesPerGas`: `FeesPerGasV1|null` - An `OBJECT` containing the fields of a `FeesPerGasV1` structure or `null` +- `gas`: `QUANTITY|null`, 64 Bits or `null` +- `to`: `DATA|null`, 20 Bytes or `null` +- `value`: `QUANTITY|null`, 256 Bits or `null` +- `input`: `DATA|null`, 0 through `MAX_CALLDATA_SIZE` bytes or `null` +- `accessList`: `Array of AccessTupleV1` - 0 through `MAX_ACCESS_LIST_SIZE` `OBJECT` entries each containing the fields of an `AccessTupleV1` structure, or `null` +- `maxPriorityFeesPerGas`: `FeesPerGasV1|null` - An `OBJECT` containing the fields of a `FeesPerGasV1` structure or `null` +- `blobVersionedHashes`: `Array of DATA|null` - 0 through `MAX_BLOB_COMMITMENTS_PER_BLOCK` `DATA` entries each containing 32 Bytes, or `null` + +`FeesPerGasV1` is defined to map onto the SSZ `FeesPerGas` `StableContainer`, as follows: + +- `regular`: `QUANTITY|null`, 256 Bits or `null` +- `blob`: `QUANTITY|null`, 256 Bits or `null` + +`AccessTupleV1` is defined to map onto the SSZ `AccessTuple` `Container`, as follows: + +- `address`: `DATA`, 20 Bytes +- `storageKeys`: `Array of DATA` - 0 through `MAX_ACCESS_LIST_STORAGE_KEYS` `DATA` entries each containing 32 Bytes + +`ExecutionSignatureV1` is defined to map onto the SSZ `ExecutionSignature` `StableContainer`, as follows: + +- `from`: `DATA|null`, 20 Bytes or `null` +- `ecdsaSignature`: `DATA|null`, 65 Bytes or `null` + +### Consensus `ExecutionPayload` changes + +When building a consensus `ExecutionPayload`, the [`transactions`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/beacon-chain.md#executionpayload) list is no longer opaque and uses the new `Transaction` type. ```python class ExecutionPayload(Container): @@ -44,40 +335,61 @@ class ExecutionPayload(Container): ... ``` -### Consensus `ExecutionPayloadHeader` changes +### SSZ `PooledTransaction` container + +During transaction gossip responses ([`PooledTransactions`](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md#pooledtransactions-0x0a)), each `Transaction` is wrapped into a `PooledTransaction`. -The [consensus `ExecutionPayloadHeader`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/capella/beacon-chain.md#executionpayloadheader) is updated for the new `ExecutionPayload.transactions` definition. +| 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 -payload_header.transactions_root = payload.transactions.hash_tree_root() +class BlobData(Container): + blobs: List[Blob, MAX_BLOB_COMMITMENTS_PER_BLOCK] + commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] + proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK] + +class PooledTransaction(StableContainer[MAX_POOLED_TRANSACTION_FIELDS]): + tx: Optional[Transaction] + blob_data: Optional[BlobData] ``` -### Execution block header changes +The additional validation constraints defined in [EIP-4844](./eip-4844.md) also apply to transactions that define `tx.payload.blob_versioned_hashes` or `blob_data`. -The [execution block header's `txs-root`](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md#block-encoding-and-validity) is updated to match the consensus `ExecutionPayloadHeader.transactions_root`. +### Transaction gossip announcements -### Transaction indexing +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)) are changed to match `ssz(PooledTransaction.active_fields())`. The separate control flow for fetching blob transactions compared to basic transactions is retained. -While a unique transaction identifier `tx_hash` is defined for each transaction, there is no on-chain commitment to this identifier for RLP transactions. Instead, transactions are ["summarized"](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md#summaries-and-expansions) by their [`hash_tree_root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md#merkleization). +Note that this change maps `active_fields` for `PooledTransaction` with `blob_data` to `0x03`, which coincides with the previous [`BLOB_TX_TYPE`](./eip-4844.md) prefix of blob RLP transactions. -```python -def compute_tx_root(tx: Transaction) -> Root: - return tx.hash_tree_root() -``` +### Networking -Note that for SSZ transactions with `tx.signature.type_ == TRANSACTION_TYPE_SSZ`, the `tx_hash` is equivalent to the `tx_root`. Like the `tx_hash`, the `tx_root` remains perpetually [stable](./eip-7495.md) across future upgrades. +When exchanging SSZ transactions 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: -It is RECOMMENDED that implementations introduce indices for tracking transactions by `tx_root`. +| Name | Value | Description | +| - | - | - | +| `SSZ_TX_TYPE` | `TransactionType(0x04)` | Endpoint specific SSZ object | + +- `Transaction`: `SSZ_TX_TYPE || snappyFramed(ssz(Transaction))` +- `PooledTransaction`: `SSZ_TX_TYPE || snappyFramed(ssz(PooledTransaction))` + +Objects are encoded using [SSZ](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) 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 emitted; 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 SHOULD 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-6404/convert.py) for a reference implementation to convert from RLP to SSZ, as well as corresponding [test cases](../assets/eip-6404/convert_tests.py). The original `sig_hash` and `tx_hash` are retained throughout the conversion process. ## Rationale -This change enables the use of SSZ transactions as defined in [EIP-6493](./eip-6493.md). +Switching to a single, unified and forward compatible transaction format within execution blocks reduces implementation complexity for client applications and smart contracts. Future use cases such as transaction inclusion proofs or submitting individual verifiable chunks of calldata to a smart contract become easier to implement with SSZ. + +Various protocol inefficiencies are also addressed. While the transaction data is hashed several times under the RLP system, including (1) `sig_hash`, (2) `tx_hash`, (3) MPT internal hash, and (4) SSZ internal hash, the normalized representation reduces the hash count. Furthermore, the `from` address no longer has to be computed using the expensive `ecrecover` operation when servicing JSON-RPC requests, and Consensus Layer implementations may drop invalid blocks early if consensus `blob_kzg_commitments` do not validate against transaction `blob_versioned_hashes`. ## Backwards Compatibility Applications that rely on the replaced MPT `transactions_root` in the block header require migration to the SSZ `transactions_root`. -While there is no on-chain commitment of the `tx_hash`, it is widely used in JSON-RPC and the [Ethereum Wire Protocol](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md) to uniquely identify transactions. The `tx_root` is a different identifier and will be required for use cases such as transaction inclusion proofs where an on-chain commitment is required. +While there is no on-chain commitment of the `tx_hash`, it is widely used in JSON-RPC and the [Ethereum Wire Protocol](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md) to uniquely identify transactions. The `tx_hash` remains stable across the conversion from RLP to SSZ. + +The conversion from RLP transactions to SSZ is lossless. The original RLP `sig_hash` and `tx_hash` can be recovered from the SSZ representation. ## Security Considerations diff --git a/EIPS/eip-6465.md b/EIPS/eip-6465.md index b0f7aa74281ba..4bed0ecb53d02 100644 --- a/EIPS/eip-6465.md +++ b/EIPS/eip-6465.md @@ -4,11 +4,11 @@ title: SSZ Withdrawals Root description: Migration of withdrawals MPT commitment to SSZ author: Etan Kissling (@etan-status), Mikhail Kalinin (@mkalinin) discussions-to: https://ethereum-magicians.org/t/eip-6465-ssz-withdrawals-root/12883 -status: Stagnant +status: Draft type: Standards Track category: Core created: 2023-02-08 -requires: 2718, 4895, 6493 +requires: 2718, 4895, 6404 --- ## Abstract @@ -41,7 +41,7 @@ Definitions from existing specifications that are used throughout this document | Name | Value | | - | - | | [`MAX_WITHDRAWALS_PER_PAYLOAD`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/capella/beacon-chain.md#execution) | `uint64(2**4)` (= 16) | -| [`TRANSACTION_TYPE_SSZ`](./eip-6493.md#eip-2718-transaction-types) | `0x04` | +| [`SSZ_TX_TYPE`](./eip-6404.md#networking) | `0x04` | ### SSZ `Withdrawal` container @@ -95,7 +95,7 @@ typed-withdrawal = withdrawal-type || withdrawal-data When exchanging SSZ withdrawals via the [Ethereum Wire Protocol](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md), the following withdrawal envelope is used: -- `Withdrawal`: `TRANSACTION_TYPE_SSZ || snappyFramed(ssz(Withdrawal))` +- `Withdrawal`: `SSZ_TX_TYPE || snappyFramed(ssz(Withdrawal))` Objects are encoded using [SSZ](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) 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 emitted; the RECOMMENDED limit to enforce per object is `8 + 8 + 20 + 8` (= 44) bytes. diff --git a/EIPS/eip-6466.md b/EIPS/eip-6466.md index 7609a1961da59..c2b6df3023991 100644 --- a/EIPS/eip-6466.md +++ b/EIPS/eip-6466.md @@ -1,61 +1,121 @@ --- eip: 6466 -title: SSZ Receipts Root -description: Migration of receipts MPT commitment to SSZ +title: SSZ Receipts +description: Migration of RLP receipts to SSZ author: Etan Kissling (@etan-status), Vitalik Buterin (@vbuterin) -discussions-to: https://ethereum-magicians.org/t/eip-6466-ssz-receipts-root/12884 -status: Stagnant +discussions-to: https://ethereum-magicians.org/t/eip-6466-ssz-receipts/12884 +status: Draft type: Standards Track category: Core created: 2023-02-08 -requires: 6404, 6493 +requires: 658, 6404 --- ## Abstract -This EIP defines a migration process of existing Merkle-Patricia Trie (MPT) commitments for receipts to [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) +This EIP defines a migration process of [EIP-2718](./eip-2718.md) Recursive-Length Prefix (RLP) receipts to [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) ## Motivation -[EIP-6404](./eip-6404.md) introduces the more modern SSZ format to the `transactions_root` of the consensus `ExecutionPayloadHeader` and the execution block header. This EIP defines the equivalent transition for `receipts_root` to add support for [EIP-6493 `Receipt`](./eip-6493.md). +RLP receipts have a number of shortcomings: -Note that in contrast to the `transactions_root` which refers to a Merkle Patricia Trie (MPT) root in execution but to an SSZ root in consensus, the `receipts_root` is already consistent and refers to the same MPT root. With this EIP, it will be changed to consistently refer to the same SSZ root. +1. **Limited proving support:** Due to receipt data being linearly hashed as part of the `receipts_root` Merkle-Patricia Trie (MPT), it is not possible to efficiently proof individual parts of receipts, such as logs. Requiring the full receipt data to be present can be prohibitive for smart contract based applications such as L2 fraud proofs or client applications verifying log data. + +2. **Unnecessary statefulness:** [EIP-658](./eip-658.md) replaced the intermediate post-state `root` from receipts with a boolean `status` code. However, `cumulativeGasUsed` is similarly stateful, unnecessarily complicating efforts to execute transactions in parallel. Furthermore, multiple receipts are required to verify the effective gas used by an individual transaction. + +3. **Incomplete data:** JSON-RPC provides `contractAddress` in the receipt for a transaction creating a new contract, but the receipt does not contain the required information to verify it. Workarounds that rely on also fetching the transaction data may not be future-proof. + +This EIP defines a universal receipt format based on SSZ to address these concerns. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -### Consensus `ExecutionPayload` changes +### Existing definitions + +Definitions from existing specifications that are used throughout this document are replicated here for reference. + +| Name | Value | +| - | - | +| [`MAX_TRANSACTIONS_PER_PAYLOAD`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/bellatrix/beacon-chain.md#execution) | `uint64(2**20)` (= 1,048,576) | +| [`BYTES_PER_LOGS_BLOOM`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/bellatrix/beacon-chain.md#execution) | `uint64(2**8)` (= 256) | +| [`SSZ_TX_TYPE`](./eip-6404.md#networking) | `0x04` | + +| Name | SSZ equivalent | +| - | - | +| [`Root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/beacon-chain.md#custom-types) | `Bytes32` | + +### `Receipt` container -When building a consensus `ExecutionPayload`, the [`receipts_root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/capella/beacon-chain.md#executionpayload) is now based on the [`Receipt`](./eip-6493.md) SSZ container. [EIP-6493](./eip-6493.md) defines how RLP receipts can be converted to SSZ. +All receipts are represented as a single, normalized SSZ container. The definition uses the `StableContainer[N]` SSZ type and `Optional[T]` as defined in [EIP-7495](./eip-7495.md). -This changes the type of `receipts_root` from an MPT [`Hash32`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/beacon-chain.md#custom-types) to an SSZ [`Root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/beacon-chain.md#custom-types). +| Name | Value | Description | +| - | - | - | +| `MAX_TOPICS_PER_LOG` | `4` | `LOG0` through `LOG4` opcodes allow 0-4 topics per log | +| `MAX_LOG_DATA_SIZE` | `uint64(2**24)` (= 16,777,216) | Maximum `data` byte length for a log | +| `MAX_LOGS_PER_RECEIPT` | `uint64(2**21)` (= 2,097,152) | Maximum number of entries within `logs` | +| `MAX_RECEIPT_FIELDS` | `uint64(2**5)` (= 32) | Maximum number of fields to which `Receipt` can ever grow in the future | ```python -class ExecutionPayload(Container): - ... - receipts_root: Root - ... +class Log(Container): + address: ExecutionAddress + topics: List[Bytes32, MAX_TOPICS_PER_LOG] + data: ByteList[MAX_LOG_DATA_SIZE] + +class Receipt(StableContainer[MAX_RECEIPT_FIELDS]): + root: Optional[Hash32] + gas_used: Optional[uint64] + contract_address: Optional[ExecutionAddress] + logs_bloom: Optional[ByteVector[BYTES_PER_LOGS_BLOOM]] + logs: Optional[List[Log, MAX_LOGS_PER_RECEIPT]] + + # EIP-658 + status: Optional[boolean] + +class HomesteadReceipt(Profile[Receipt]): + root: Hash32 + gas_used: uint64 + contract_address: Optional[ExecutionAddress] + logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs: List[Log, MAX_LOGS_PER_RECEIPT] + +class BasicReceipt(Profile[Receipt]): + gas_used: uint64 + contract_address: Optional[ExecutionAddress] + logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] + logs: List[Log, MAX_LOGS_PER_RECEIPT] + status: boolean + +def select_receipt_profile(value: Receipt) -> Type[Profile]: + if value.status is not None: + return BasicReceipt + + return HomesteadReceipt ``` -To compute the `receipts_root`, the list of individual `Receipt` containers is represented as an SSZ `List`. +![Receipt merkleization](../assets/eip-6466/receipt.png) -| Name | Value | -| - | - | -| [`MAX_TRANSACTIONS_PER_PAYLOAD`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/bellatrix/beacon-chain.md#execution) | `uint64(2**20)` (= 1,048,576) | +### Execution block header changes + +The [execution block header's `receipts-root`](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md#block-encoding-and-validity) is transitioned from MPT to SSZ. ```python receipts = List[Receipt, MAX_TRANSACTIONS_PER_PAYLOAD]( receipt_0, receipt_1, receipt_2, ...) -payload.receipts_root = receipts.hash_tree_root() +block_header.receipts_root = receipts.hash_tree_root() ``` -### Consensus `ExecutionPayloadHeader` changes +### Consensus `ExecutionPayload` changes -The [consensus `ExecutionPayloadHeader`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/capella/beacon-chain.md#executionpayloadheader) is updated to match the new `ExecutionPayload.receipts_root` definition. +When building a consensus `ExecutionPayload`, the [`receipts_root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/deneb/beacon-chain.md#executionpayload) is now based on the `Receipt` type, changing the type of `receipts_root` from an MPT [`Hash32`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/beacon-chain.md#custom-types) to an SSZ [`Root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/beacon-chain.md#custom-types). ```python +class ExecutionPayload(Container): + ... + receipts_root: Root + ... + class ExecutionPayloadHeader(Container): ... receipts_root: Root @@ -66,18 +126,24 @@ class ExecutionPayloadHeader(Container): payload_header.receipts_root = payload.receipts_root ``` -### Execution block header changes +### Networking -The [execution block header's `receipts-root`](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md#block-encoding-and-validity) is updated to match the consensus `ExecutionPayloadHeader.receipts_root`. +When exchanging SSZ receipts via the [Ethereum Wire Protocol](https://github.com/ethereum/devp2p/blob/6b259a7003b4bfb18365ba690f4b00ba8a26393b/caps/eth.md), the following [EIP-2718](./eip-2718.md) compatible envelope is used: + +- `Receipt`: `SSZ_TX_TYPE || snappyFramed(ssz(Receipt))` + +Objects are encoded using [SSZ](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) 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 emitted; 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. ## Rationale -This change enables the use of SSZ transactions as defined in [EIP-6493](./eip-6493.md). +SSZ merkleization allows verification of individual chunks of receipt data, reducing complexity for client applications and smart contracts. Additionally, SSZ [`StableContainer`](./eip-7495.md) enables unification of the receipt format across all [EIP-2718](./eip-2718.md) transaction types and provides forward compatibility. ## Backwards Compatibility Applications that rely on the replaced MPT `receipts_root` in the block header require migration to the SSZ `receipts_root`. +Applications using verified `cumulativeGasUsed` values have to compute the value from prior receipts. + ## Security Considerations None diff --git a/EIPS/eip-6493.md b/EIPS/eip-6493.md index a92ba4a2320a1..ff46446f66f12 100644 --- a/EIPS/eip-6493.md +++ b/EIPS/eip-6493.md @@ -1,231 +1,70 @@ --- eip: 6493 title: SSZ Transaction Signature Scheme -description: Signature scheme for SSZ transactions +description: Signature scheme for native SSZ transactions author: Etan Kissling (@etan-status), Matt Garnett (@lightclient), Vitalik Buterin (@vbuterin) discussions-to: https://ethereum-magicians.org/t/eip-6493-ssz-transaction-signature-scheme/13050 status: Draft type: Standards Track category: Core created: 2023-02-24 -requires: 155, 191, 1559, 2718, 2930, 4844, 5793, 7495 +requires: 6404, 6466 --- ## Abstract -This EIP defines a signature scheme for [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) encoded transactions. +This EIP defines a signature scheme for native [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) encoded transactions. ## Motivation -For each transaction, two perpetual hashes are derived. - -1. `sig_hash` is the hash of the unsigned transaction that is being signed. It is crucial that no two valid transactions ever share the same `sig_hash`. - -2. `tx_hash` is a unique identifier to refer to a signed transaction. This hash is used to refer to a transaction within the mempool, and remains stable after a transaction is included into a block. - -For existing [EIP-2718](./eip-2718.md) Recursive-Length Prefix (RLP) transactions, these hashes are based on a linear keccak256 hash across their serialization. - -For [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) transaction types, an alternative signature scheme based on SHA256 Merkle trees is defined in this EIP. - -Furthermore, this EIP defines a conversion mechanism to achieve a consistent representation across both RLP and SSZ transactions and receipts. +[EIP-6404](./eip-6404.md) introduces SSZ transactions by converting from RLP transactions. Defining a signature scheme for native SSZ transactions further reduces required conversions and unlocks the forward compatibility benefits of SSZ [`StableContainer`](./eip-7495.md). ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -### [EIP-2718](./eip-2718.md) transaction types - -| Name | SSZ equivalent | Description | -| - | - | - | -| `TransactionType` | `uint8` | [EIP-2718](./eip-2718.md) transaction type, range `[0x00, 0x7F]` | - -The values `0x00` and `0x04` are marked as reserved [EIP-2718](./eip-2718.md) transaction types. - -- `0x00` indicates an [EIP-2718](./eip-2718.md) `LegacyTransaction`. -- `0x04` indicates an SSZ `Transaction` as defined in this EIP. - -| Name | Value | Description | -| - | - | - | -| (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 | -| `TRANSACTION_TYPE_SSZ` | `TransactionType(0x04)` | SSZ `Transaction` | - -Note that `0x19` is reserved to prevent collision with [ERC-191](./eip-191.md) signed data. - -### Existing definitions - -Definitions from existing specifications that are used throughout this document are replicated here for reference. - -| Name | SSZ equivalent | -| - | - | -| [`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` | +### Transaction signature scheme -| 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) | +Native SSZ transactions are based on the `TransactionPayload` and `Transaction` types defined in [EIP-6404](./eip-6404.md) and emit an [EIP-6466](./eip-6466.md) `Receipt`. To distinguish native SSZ transactions from those converted from RLP, native SSZ transactions do not set an RLP `TransactionType` in their `TransactionPayload`. -### SSZ `Transaction` container +All native SSZ transactions follow an identical scheme based on [`hash_tree_root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md#merkleization) to compute their signing hash (`sig_hash`) and unique identifier (`tx_hash`). -All SSZ transactions are represented as a single, normalized SSZ container. The definition uses the `StableContainer[N]` SSZ type and `Optional[T]` as defined in [EIP-7495](./eip-7495.md). +Additional information is mixed into `sig_hash` to uniquely identify the underlying specification and avoid hash collisions across different signature kinds. Vendor-defined networks MUST use a different `DomainType` for signing custom transaction types. | Name | Value | Description | | - | - | - | -| `MAX_CALLDATA_SIZE` | `uint64(2**24)` (= 16,777,216) | Maximum `input` calldata byte length for a transaction | -| `MAX_ACCESS_LIST_STORAGE_KEYS` | `uint64(2**19)` (= 524,288) | Maximum number of storage keys within an access tuple | -| `MAX_ACCESS_LIST_SIZE` | `uint64(2**19)` (= 524,288) | Maximum number of access tuples within an `access_list` | -| `ECDSA_SIGNATURE_SIZE` | `32 + 32 + 1` (= 65) | Byte length of an ECDSA (secp256k1) signature | -| `MAX_FEES_PER_GAS_FIELDS` | `uint64(2**4)` (= 16) | Maximum number of fields to which `FeesPerGas` can ever grow in the future | -| `MAX_TRANSACTION_PAYLOAD_FIELDS` | `uint64(2**5)` (= 32) | Maximum number of fields to which `TransactionPayload` can ever grow in the future | -| `MAX_TRANSACTION_SIGNATURE_FIELDS` | `uint64(2**4)` (= 16) | Maximum number of fields to which `TransactionSignature` can ever grow in the future | - -| Name | SSZ equivalent | Description | -| - | - | - | -| `ChainId` | `uint64` | [EIP-155](./eip-155.md) chain ID at time of signature | -| `FeePerGas` | `uint256` | Fee per unit of gas, cannot overflow across an entire block | +| `DOMAIN_TX_SSZ` | `DomainType('0x00000080)` | [`DomainType`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/beacon-chain.md#custom-types) for signing native SSZ transactions compatible with this EIP | ```python -class FeesPerGas(StableContainer[MAX_FEES_PER_GAS_FIELDS]): - regular: Optional[FeePerGas] - - # EIP-4844 - blob: Optional[FeePerGas] - -class AccessTuple(Container): - address: ExecutionAddress - storage_keys: List[Hash32, MAX_ACCESS_LIST_STORAGE_KEYS] - -class TransactionPayload(StableContainer[MAX_TRANSACTION_PAYLOAD_FIELDS]): - # EIP-2718 - type_: Optional[TransactionType] - - # EIP-155 - chain_id: Optional[ChainId] - - nonce: Optional[uint64] - max_fees_per_gas: Optional[FeesPerGas] - gas: Optional[uint64] - to: Optional[ExecutionAddress] - value: Optional[uint256] - input_: Optional[ByteList[MAX_CALLDATA_SIZE]] - - # EIP-2930 - access_list: Optional[List[AccessTuple, MAX_ACCESS_LIST_SIZE]] - - # EIP-1559 - max_priority_fees_per_gas: Optional[FeesPerGas] - - # EIP-4844 - blob_versioned_hashes: Optional[List[VersionedHash, MAX_BLOB_COMMITMENTS_PER_BLOCK]] +class ExecutionSigningData(Container): + object_root: Root + domain_type: DomainType -class TransactionSignature(StableContainer[MAX_TRANSACTION_SIGNATURE_FIELDS]): - from_: Optional[ExecutionAddress] - ecdsa_signature: Optional[ByteVector[ECDSA_SIGNATURE_SIZE]] +def compute_ssz_sig_hash(payload: TransactionPayload) -> Hash32: + return Hash32(ExecutionSigningData( + object_root=payload.hash_tree_root(), + domain=DOMAIN_TX_SSZ, + ).hash_tree_root()) -class Transaction(Container): - payload: TransactionPayload - signature: TransactionSignature +def compute_ssz_tx_hash(tx: Transaction) -> Hash32: + assert tx.payload.type_ is None + return Hash32(tx.hash_tree_root()) ``` -Valid transaction types can be defined using [EIP-7495](./eip-7495.md) `Profile`. - -```python -class BasicFeesPerGas(Profile[FeesPerGas]): - regular: FeePerGas - -class BlobFeesPerGas(Profile[FeesPerGas]): - regular: FeePerGas - blob: FeePerGas - -class EcdsaTransactionSignature(Profile[TransactionSignature]): - from_: ExecutionAddress - ecdsa_signature: ByteVector[ECDSA_SIGNATURE_SIZE] - -class ReplayableTransactionPayload(Profile[TransactionPayload]): - type_: TransactionType - nonce: uint64 - max_fees_per_gas: BasicFeesPerGas - gas: uint64 - to: Optional[ExecutionAddress] - value: uint256 - input_: ByteList[MAX_CALLDATA_SIZE] - -class ReplayableTransaction(Container): - payload: ReplayableTransactionPayload - signature: EcdsaTransactionSignature +### JSON-RPC -class LegacyTransactionPayload(Profile[TransactionPayload]): - type_: TransactionType - chain_id: ChainId - nonce: uint64 - max_fees_per_gas: BasicFeesPerGas - gas: uint64 - to: Optional[ExecutionAddress] - value: uint256 - input_: ByteList[MAX_CALLDATA_SIZE] - -class LegacyTransaction(Container): - payload: LegacyTransactionPayload - signature: EcdsaTransactionSignature - -class Eip2930TransactionPayload(Profile[TransactionPayload]): - type_: TransactionType - chain_id: ChainId - nonce: uint64 - max_fees_per_gas: BasicFeesPerGas - gas: uint64 - to: Optional[ExecutionAddress] - value: uint256 - input_: ByteList[MAX_CALLDATA_SIZE] - access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] - -class Eip2930Transaction(Container): - payload: Eip2930TransactionPayload - signature: EcdsaTransactionSignature +Certain JSON-RPC endpoints such as `eth_getTransactionByHash` indicate the corresponding [EIP-2718](./eip-2718.md) envelope type prefix in a `type` field. -class Eip1559TransactionPayload(Profile[TransactionPayload]): - type_: TransactionType - chain_id: ChainId - nonce: uint64 - max_fees_per_gas: BasicFeesPerGas - gas: uint64 - to: Optional[ExecutionAddress] - value: uint256 - input_: ByteList[MAX_CALLDATA_SIZE] - access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] - max_priority_fees_per_gas: BasicFeesPerGas +When representing SSZ transactions on such endpoints, `SSZ_TX_TYPE` SHOULD be indicated as their `type`, as defined in [EIP-6404](./eip-6404.md#networking). Omitting the `type` is NOT RECOMMENDED as certain client applications could confuse the omission with untyped `LegacyTransaction`. -class Eip1559Transaction(Container): - payload: Eip1559TransactionPayload - signature: EcdsaTransactionSignature +### `Transaction` profiles -class Eip4844TransactionPayload(Profile[TransactionPayload]): - type_: TransactionType - chain_id: ChainId - nonce: uint64 - max_fees_per_gas: BlobFeesPerGas - gas: uint64 - to: ExecutionAddress - value: uint256 - input_: ByteList[MAX_CALLDATA_SIZE] - access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] - max_priority_fees_per_gas: BlobFeesPerGas - blob_versioned_hashes: List[VersionedHash, MAX_BLOB_COMMITMENTS_PER_BLOCK] +New [EIP-7495](./eip-7495.md) `Profile` definitions are introduced to represent native SSZ transactions: -class Eip4844Transaction(Container): - payload: Eip4844TransactionPayload - signature: EcdsaTransactionSignature +- `BasicTransaction` shares the functionality of [EIP-1559](./eip-1559.md#specification) fee market transactions +- `BlobTransaction` shares the functionality of [EIP-4844](./eip-4844.md#parameters) blob transactions +```python class BasicTransactionPayload(Profile[TransactionPayload]): chain_id: ChainId nonce: uint64 @@ -239,7 +78,7 @@ class BasicTransactionPayload(Profile[TransactionPayload]): class BasicTransaction(Container): payload: BasicTransactionPayload - signature: EcdsaTransactionSignature + signature: EcdsaExecutionSignature class BlobTransactionPayload(Profile[TransactionPayload]): chain_id: ChainId @@ -255,319 +94,46 @@ class BlobTransactionPayload(Profile[TransactionPayload]): class BlobTransaction(Container): payload: BlobTransactionPayload - signature: EcdsaTransactionSignature - -def select_transaction_profile(cls, value: Transaction) -> Type[Profile]: - if value.payload.type_ is None: - if value.payload.blob_versioned_hashes is not None: - return BlobTransaction - return BasicTransaction - - if value.payload.type_ == TRANSACTION_TYPE_EIP4844: - return Eip4844Transaction - - if value.payload.type_ == TRANSACTION_TYPE_EIP1559: - return Eip1559Transaction - - if value.payload.type_ == TRANSACTION_TYPE_EIP2930: - return Eip2930Transaction - - if value.payload.chain_id is not None: - return LegacyTransaction - - return ReplayableTransaction + signature: EcdsaExecutionSignature ``` -Future specifications MAY: - -- Append fields to `TransactionPayload` and `TransactionSignature` -- Adjust `Profile` types and update `select_transaction_profile` logic - -Such changes [do not affect](./eip-7495.md) how existing transactions serialize or merkleize. - -![Transaction merkleization](../assets/eip-6493/transaction.png) - -### Transaction signature scheme - -When an SSZ transaction is signed, additional information is mixed into the `sig_hash` to uniquely identify the underlying specifications. If other networks define additional transaction types, they MUST use a different `DomainType` for signing SSZ data. - -| Name | Value | Description | -| - | - | - | -| `DOMAIN_TRANSACTION_SSZ` | `DomainType('0x04000080)` | [`DomainType`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/phase0/beacon-chain.md#custom-types) for signing SSZ transactions compatible with this EIP | - -The hash to sign `sig_hash` and the unique transaction identifier `tx_hash` are computed using [`hash_tree_root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md#merkleization). - -```python -class ExecutionSigningData(Container): - object_root: Root - domain_type: DomainType - -def compute_ssz_sig_hash(payload: TransactionPayload) -> Hash32: - return Hash32(ExecutionSigningData( - object_root=payload.hash_tree_root(), - domain=DOMAIN_TRANSACTION_SSZ, - ).hash_tree_root()) - -def compute_ssz_tx_hash(tx: Transaction) -> Hash32: - assert tx.payload.type_ == TRANSACTION_TYPE_SSZ - return Hash32(tx.hash_tree_root()) -``` - -### Transaction validation - -As part of `Transaction` validation, the `from` address MUST be checked for consistency with the `ecdsa_signature`. +The `identify_transaction_profile` helper from [EIP-6404](./eip-6404.md) is updated to support native SSZ transactions. ```python -def ecdsa_pack_signature(y_parity: bool, - r: uint256, - s: uint256) -> ByteVector[ECDSA_SIGNATURE_SIZE]: - return r.to_bytes(32, 'big') + s.to_bytes(32, 'big') + bytes([0x01 if y_parity else 0x00]) - -def ecdsa_unpack_signature(signature: ByteVector[ECDSA_SIGNATURE_SIZE]) -> tuple[bool, uint256, uint256]: - y_parity = signature[64] != 0 - r = uint256.from_bytes(signature[0:32], 'big') - s = uint256.from_bytes(signature[32:64], 'big') - return (y_parity, r, s) - -def ecdsa_validate_signature(signature: ByteVector[ECDSA_SIGNATURE_SIZE]): - SECP256K1N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 - assert len(signature) == 65 - assert signature[64] in (0, 1) - _, r, s = ecdsa_unpack_signature(signature) - assert 0 < r < SECP256K1N - assert 0 < s < SECP256K1N - -def ecdsa_recover_from_address(signature: ByteVector[ECDSA_SIGNATURE_SIZE], - sig_hash: Hash32) -> ExecutionAddress: - ecdsa = ECDSA() - recover_sig = ecdsa.ecdsa_recoverable_deserialize(signature[0:64], signature[64]) - public_key = PublicKey(ecdsa.ecdsa_recover(sig_hash, recover_sig, raw=True)) - uncompressed = public_key.serialize(compressed=False) - return ExecutionAddress(keccak(uncompressed[1:])[12:]) - -def validate_transaction(tx): - ecdsa_validate_signature(tx.signature.ecdsa_signature) - assert tx.signature.from_ == ecdsa_recover_from_address( - tx.signature.ecdsa_signature, - compute_sig_hash(tx), - ) -``` - -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 `Transaction` is wrapped into a `PooledTransaction`. The definition uses the `StableContainer[N]` SSZ type and `Optional[T]` 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 BlobData(Container): - blobs: List[Blob, MAX_BLOB_COMMITMENTS_PER_BLOCK] - commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] - proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK] - -class PooledTransaction(StableContainer[MAX_POOLED_TRANSACTION_FIELDS]): - tx: Transaction - blob_data: Optional[BlobData] -``` - -The same additional validation constraints as defined in [EIP-4844](./eip-4844.md) also apply to transactions that define `tx.payload.blob_versioned_hashes` or `blob_data`. - -Future specifications MAY: - -- Add fields to the end of `PooledTransactionPayload` -- Convert existing fields to `Optional` - -Such changes [do not affect](./eip-7495.md) how existing pooled transactions serialize, merkleize, or validate. +def identify_transaction_profile(tx: Transaction) -> Type[Profile]: + if tx.payload.type_ is None: + if tx.payload.blob_versioned_hashes is not None: + return BlobTransaction -### SSZ `Receipt` container + return BasicTransaction -All SSZ receipts are represented as a single, normalized SSZ container. The definition uses the `StableContainer[N]` SSZ type and `Optional[T]` as defined in [EIP-7495](./eip-7495.md). + else: + if tx.payload.type_ == BLOB_TX_TYPE: + return RlpBlobTransaction -| Name | Value | Description | -| - | - | - | -| `MAX_TOPICS_PER_LOG` | `4` | `LOG0` through `LOG4` opcodes allow 0-4 topics per log | -| `MAX_LOG_DATA_SIZE` | `uint64(2**24)` (= 16,777,216) | Maximum `data` byte length for a log | -| `MAX_LOGS_PER_RECEIPT` | `uint64(2**21)` (= 2,097,152) | Maximum number of entries within `logs` | -| `MAX_RECEIPT_FIELDS` | `uint64(2**5)` (= 32) | Maximum number of fields to which `Receipt` can ever grow in the future | + if tx.payload.type_ == FEE_MARKET_TX_TYPE: + return RlpFeeMarketTransaction -```python -class Log(Container): - address: ExecutionAddress - topics: List[Bytes32, MAX_TOPICS_PER_LOG] - data: ByteList[MAX_LOG_DATA_SIZE] - -class Receipt(StableContainer[MAX_RECEIPT_FIELDS]): - root: Optional[Hash32] - gas_used: Optional[uint64] - contract_address: Optional[ExecutionAddress] - logs_bloom: Optional[ByteVector[BYTES_PER_LOGS_BLOOM]] - logs: Optional[List[Log, MAX_LOGS_PER_RECEIPT]] - - # EIP-658 - status: Optional[boolean] -``` + if tx.payload.type_ == ACCESS_LIST_TX_TYPE: + return RlpAccessListTransaction -Valid receipt types can be defined using [EIP-7495](./eip-7495.md) `Profile`. + if tx.payload.type_ == LEGACY_TX_TYPE: + return RlpLegacyTransaction -```python -class HomesteadReceipt(Profile[Receipt]): - root: Hash32 - gas_used: uint64 - contract_address: Optional[ExecutionAddress] - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - logs: List[Log, MAX_LOGS_PER_RECEIPT] - -class BasicReceipt(Profile[Receipt]): - gas_used: uint64 - contract_address: Optional[ExecutionAddress] - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - logs: List[Log, MAX_LOGS_PER_RECEIPT] - status: boolean - -def select_receipt_profile(value: Receipt) -> Type[Profile]: - if value.status is not None: - return BasicReceipt - - return HomesteadReceipt + raise Exception(f'Unsupported transaction: {tx}') ``` -Future specifications MAY: - -- Add fields to the end of `Receipt` -- Adjust `Profile` types and update `select_receipt_profile` logic - -Such changes [do not affect](./eip-7495.md) how existing receipts serialize or merkleize. - -![Receipt merkleization](../assets/eip-6493/receipt.png) - -### Networking - -When exchanging SSZ 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: - -- `Transaction`: `TRANSACTION_TYPE_SSZ || snappyFramed(ssz)` -- `PooledTransaction`: `TRANSACTION_TYPE_SSZ || snappyFramed(ssz(PooledTransaction))` -- `Receipt`: `TRANSACTION_TYPE_SSZ || snappyFramed(ssz(Receipt))` - -Objects are encoded using [SSZ](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md) 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 emitted; 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 SHOULD 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_data` | - -### Engine API - -When exchanging via the engine API, the structure of the `transactions` field in `ExecutionPayload` versions adopting this EIP is changed from `Array of DATA` to `Array of TransactionV1`. - -`TransactionV1` is defined to map onto the SSZ `Transaction` `StableContainer`, as follows: - -- `payload`: `TransactionPayloadV1` - An `OBJECT` containing the fields of a `TransactionPayloadV1` structure -- `signature`: `TransactionSignatureV1` - An `OBJECT` containing the fields of a `TransactionSignatureV1` structure - -`TransactionPayloadV1` is defined to map onto the SSZ `TransactionPayload` `StableContainer`, as follows: - -- `type`: `QUANTITY|null`, 8 Bits or `null` -- `chainId`: `QUANTITY|null`, 64 Bits or `null` -- `nonce`: `QUANTITY|null`, 64 Bits or `null` -- `maxFeesPerGas`: `FeesPerGasV1|null` - An `OBJECT` containing the fields of a `FeesPerGasV1` structure or `null` -- `gas`: `QUANTITY|null`, 64 Bits or `null` -- `to`: `DATA|null`, 20 Bytes or `null` -- `value`: `QUANTITY|null`, 256 Bits or `null` -- `input`: `DATA|null`, 0 through `MAX_CALLDATA_SIZE` bytes or `null` -- `accessList`: `Array of AccessTupleV1` - 0 through `MAX_ACCESS_LIST_SIZE` `OBJECT` entries each containing the fields of an `AccessTupleV1` structure, or `null` -- `maxPriorityFeesPerGas`: `FeesPerGasV1|null` - An `OBJECT` containing the fields of a `FeesPerGasV1` structure or `null` -- `blobVersionedHashes`: `Array of DATA|null` - 0 through `MAX_BLOB_COMMITMENTS_PER_BLOCK` `DATA` entries each containing 32 Bytes, or `null` - -`FeesPerGasV1` is defined to map onto the SSZ `FeesPerGas` `StableContainer`, as follows: - -- `regular`: `QUANTITY|null`, 256 Bits or `null` -- `blob`: `QUANTITY|null`, 256 Bits or `null` - -`AccessTupleV1` is defined to map onto the SSZ `AccessTuple` `Container`, as follows: - -- `address`: `DATA`, 20 Bytes -- `storageKeys`: `Array of DATA` - 0 through `MAX_ACCESS_LIST_STORAGE_KEYS` `DATA` entries each containing 32 Bytes - -`TransactionSignatureV1` is defined to map onto the SSZ `TransactionSignature` `StableContainer`, as follows: - -- `from`: `DATA|null`, 20 Bytes or `null` -- `ecdsaSignature`: `DATA|null`, 65 Bytes or `null` - ## Rationale -### Why SSZ transactions? - -1. **Transaction inclusion proofs:** Currently, there is no commitment to the transaction hash stored on chain. Therefore, proving inclusion of a certain transaction within a block requires sending the entire transaction body, and proving a list of all transaction hashes within a block requires sending _all_ transaction bodies. With SSZ, a transaction can be ["summarized"](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md#summaries-and-expansions) by it's [`hash_tree_root`](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/simple-serialize.md#merkleization), unlocking transaction root proofs without sending all transaction bodies, and compact transaction inclusion proofs by root. - -2. **Better for light clients:** With SSZ, individual fields of a transaction or receipt can be proven. This allows light clients to obtain only fields relevant to them. Furthermore, common fields fields always merkleize at the same [generalized indices](https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/ssz/merkle-proofs.md), allowing existing verification logic to continue working even when future updates introduce additional transaction or receipt fields. - -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 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 `Transaction`. - -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 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? - -Computing the address of a newly created contract requires RLP encoding and keccak hashing. Adding a commitment on-chain avoids requiring API clients to implement those formats. - -Even though the `contract_address` is statically determinable from the corresponding `Transaction` alone, including it in the `Receipt` allows the mechanism by which it is computed to change in the future. - -### Why the `ExecutionSigningData`? - -If other SSZ objects are being signed in the future, e.g., messages, it must be ensured that their hashes do not collide with transaction `sig_hash`. Mixing in a constant that indicates that `sig_hash` pertains to an SSZ transaction prevents such hash collisions. - -### What about EIP-2718 transaction types? - -All SSZ transactions (including future ones) share the single [EIP-2718](./eip-2718.md) transaction type `TRANSACTION_TYPE_SSZ`. Future features can introduce new optional fields as well as new allowed combination of optional fields, as determined by `select_transaction_profile`. - -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 `Transaction` 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. - -### What about `Log` data in receipts? - -`Log` data is formatted according to the Ethereum contract ABI. Merkleizing log data according to its original structure would be more useful than merkleizing it as a `ByteVector`. However, the data structure is determined by the log event signature, of which only the hash is known. As the hash preimages are erased from emitted EVM logs, it is not reliably possible to recover the original log event signature. Therefore, log data and transaction input data are provided as a `ByteVector` for now. +The SSZ signature scheme reduces hashing overhead and ensures that `tx_hash` commitments are available on-chain. It also provides a flexible basis for future transaction functionality. ## Backwards Compatibility -The new transaction signature scheme is solely used for SSZ transactions. - -Existing RLP transactions can be converted to SSZ transactions. Their original `sig_hash` and `tx_hash` can be recovered from their SSZ representation. - -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. +The new transaction signature scheme is solely used for SSZ transactions and is represented using a different [EIP-2718](./eip-2718.md) envelope type prefix as existing RLP transactions. ## Security Considerations -SSZ signatures MUST NOT collide with existing RLP transaction and message hashes. +SSZ signatures MUST NOT collide with RLP transaction and message hashes. As RLP messages are hashed using keccak256, and all SSZ objects are hashed using SHA256. These two hashing algorithms are both considered cryptographically secure and are based on fundamentally different approaches, minimizing the risk of hash collision between those two hashing algorithms. diff --git a/assets/eip-6404/convert.py b/assets/eip-6404/convert.py new file mode 100644 index 0000000000000..556cd026a742f --- /dev/null +++ b/assets/eip-6404/convert.py @@ -0,0 +1,149 @@ +from rlp import decode +from rlp_types import * +from ssz_types import * + +def upgrade_rlp_transaction_to_ssz(pre_bytes: bytes): + type_ = pre_bytes[0] + + if type_ == 0x03: # EIP-4844 + pre = decode(pre_bytes[1:], BlobRlpTransaction) + assert pre.y_parity in (0, 1) + ecdsa_signature = ecdsa_pack_signature( + pre.y_parity != 0, + pre.r, + pre.s, + ) + from_ = ecdsa_recover_from_address(ecdsa_signature, compute_blob_sig_hash(pre)) + + return RlpBlobTransaction( + payload=RlpBlobTransactionPayload( + type_=BLOB_TX_TYPE, + chain_id=pre.chain_id, + nonce=pre.nonce, + max_fees_per_gas=BlobFeesPerGas( + regular=pre.max_fee_per_gas, + blob=pre.max_fee_per_blob_gas, + ), + gas=pre.gas, + to=ExecutionAddress(pre.to), + value=pre.value, + input_=pre.data, + access_list=[AccessTuple( + address=access_tuple[0], + storage_keys=access_tuple[1] + ) for access_tuple in pre.access_list], + max_priority_fees_per_gas=BlobFeesPerGas( + regular=pre.max_priority_fee_per_gas, + blob=FeePerGas(0), + ), + blob_versioned_hashes=pre.blob_versioned_hashes, + ), + signature=EcdsaExecutionSignature( + from_=from_, + ecdsa_signature=ecdsa_signature, + ), + ) + + if type_ == 0x02: # EIP-1559 + pre = decode(pre_bytes[1:], FeeMarketRlpTransaction) + assert pre.y_parity in (0, 1) + ecdsa_signature = ecdsa_pack_signature( + pre.y_parity != 0, + pre.r, + pre.s, + ) + from_ = ecdsa_recover_from_address(ecdsa_signature, compute_fee_market_sig_hash(pre)) + + return RlpFeeMarketTransaction( + payload=RlpFeeMarketTransactionPayload( + type_=FEE_MARKET_TX_TYPE, + chain_id=pre.chain_id, + nonce=pre.nonce, + max_fees_per_gas=BasicFeesPerGas( + regular=pre.max_fee_per_gas, + ), + gas=pre.gas, + to=ExecutionAddress(pre.to) if len(pre.to) > 0 else None, + value=pre.value, + input_=pre.data, + access_list=[AccessTuple( + address=access_tuple[0], + storage_keys=access_tuple[1] + ) for access_tuple in pre.access_list], + max_priority_fees_per_gas=BasicFeesPerGas( + regular=pre.max_priority_fee_per_gas, + ), + ), + signature=EcdsaExecutionSignature( + from_=from_, + ecdsa_signature=ecdsa_signature, + ), + ) + + if type_ == 0x01: # EIP-2930 + pre = decode(pre_bytes[1:], AccessListRlpTransaction) + assert pre.y_parity in (0, 1) + ecdsa_signature = ecdsa_pack_signature( + pre.y_parity != 0, + pre.r, + pre.s + ) + from_ = ecdsa_recover_from_address(ecdsa_signature, compute_access_list_sig_hash(pre)) + + return RlpAccessListTransaction( + payload=RlpAccessListTransactionPayload( + type_=ACCESS_LIST_TX_TYPE, + chain_id=pre.chain_id, + nonce=pre.nonce, + max_fees_per_gas=BasicFeesPerGas( + regular=pre.gas_price, + ), + gas=pre.gas, + to=ExecutionAddress(pre.to) if len(pre.to) > 0 else None, + value=pre.value, + input_=pre.data, + access_list=[AccessTuple( + address=access_tuple[0], + storage_keys=access_tuple[1] + ) for access_tuple in pre.access_list], + ), + signature=EcdsaExecutionSignature( + from_=from_, + ecdsa_signature=ecdsa_signature, + ), + ) + + if 0xc0 <= type_ <= 0xfe: # Legacy + pre = decode(pre_bytes, LegacyRlpTransaction) + ecdsa_signature = ecdsa_pack_signature( + (pre.v & 0x1) == 0, + pre.r, + pre.s, + ) + from_ = ecdsa_recover_from_address(ecdsa_signature, compute_legacy_sig_hash(pre)) + + if (pre.v not in (27, 28)): # EIP-155 + chain_id = ((pre.v - 35) >> 1) + else: + chain_id = None + + return RlpLegacyTransaction( + payload=RlpLegacyTransactionPayload( + type_=LEGACY_TX_TYPE, + chain_id=chain_id, + nonce=pre.nonce, + max_fees_per_gas=BasicFeesPerGas( + regular=pre.gas_price, + ), + gas=pre.gas, + to=ExecutionAddress(pre.to) if len(pre.to) > 0 else None, + value=pre.value, + input_=pre.data, + ), + signature=EcdsaExecutionSignature( + from_=from_, + ecdsa_signature=ecdsa_signature, + ), + ) + + assert False diff --git a/assets/eip-6493/convert_tests.py b/assets/eip-6404/convert_tests.py similarity index 64% rename from assets/eip-6493/convert_tests.py rename to assets/eip-6404/convert_tests.py index 93ad463c035c1..e8b3a94c51605 100644 --- a/assets/eip-6493/convert_tests.py +++ b/assets/eip-6404/convert_tests.py @@ -1,93 +1,68 @@ from dataclasses import dataclass from convert import * +from tx_hashes import compute_tx_hash @dataclass class Test: + tx_profile: Type[Profile] rlp_tx_hash: Hash32 rlp_tx_bytes: bytes - rlp_receipt_bytes: bytes - ssz_tx_root: Root + ssz_tx_root: Hash32 ssz_tx_bytes: bytes - ssz_receipt_bytes: bytes tests = [ Test( + tx_profile=RlpLegacyTransaction, rlp_tx_hash=Hash32(bytes.fromhex("5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060")), rlp_tx_bytes=bytes.fromhex("f86780862d79883d2000825208945df9b87991262f6ba471f09758cde1c0fc1de734827a69801ca088ff6cf0fefd94db46111149ae4bfc179e9b94721fffd821d38d16464b3f71d0a045e0aff800961cfce805daef7016b9b675c137a6a41a548f7b60a3484c06a33a"), - rlp_receipt_bytes=bytes.fromhex("f90128a096a8e009d2b88b1483e6941e6812e32263b05683fac202abc622a3e31aed1957825208b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0"), - ssz_tx_root=Root(bytes.fromhex("d8aa0c09b136ea863cd5dd3fe21d72226aaa3f30ac6ab56de1ea8f0a61b100e2")), + ssz_tx_root=Hash32(bytes.fromhex("d8aa0c09b136ea863cd5dd3fe21d72226aaa3f30ac6ab56de1ea8f0a61b100e2")), ssz_tx_bytes=bytes.fromhex("080000007b000000fd0000000000000000000000004d00000008520000000000005df9b87991262f6ba471f09758cde1c0fc1de734697a0000000000000000000000000000000000000000000000000000000000006f000000010000203d88792d00000000000000000000000000000000000000000000000000000300a1e4380a3b1f749673e270229993ee55f35663b488ff6cf0fefd94db46111149ae4bfc179e9b94721fffd821d38d16464b3f71d045e0aff800961cfce805daef7016b9b675c137a6a41a548f7b60a3484c06a33a01"), - ssz_receipt_bytes=bytes.fromhex("1b00000096a8e009d2b88b1483e6941e6812e32263b05683fac202abc622a3e31aed19570852000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c010000"), ), Test( + tx_profile=RlpLegacyTransaction, rlp_tx_hash=Hash32(bytes.fromhex("e9e91f1ee4b56c0df2e9f06c2b8c27c6076195a88a7b8537ba8313d80e6f124e")), rlp_tx_bytes=bytes.fromhex("f86e8243eb850df847580082c35094df190dc7190dfba737d7777a163445b7fff161338806113a84987be800801ca03b08715b4403c792b8c7567edea634088bedcd7f60d9352b1f16c69830f3afd5a010b9afb67d2ec8b956f0e1dbc07eb79152904f3a7bf789fc869db56320adfe09"), - rlp_receipt_bytes=bytes.fromhex("f901080182a410b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0"), - ssz_tx_root=Root(bytes.fromhex("78526295a3926d954a455a06a7eff6c84098b14294d4c8bfc3303d1836ace217")), + ssz_tx_root=Hash32(bytes.fromhex("78526295a3926d954a455a06a7eff6c84098b14294d4c8bfc3303d1836ace217")), ssz_tx_bytes=bytes.fromhex("080000007b000000fd00000000eb430000000000004d00000050c3000000000000df190dc7190dfba737d7777a163445b7fff1613300e87b98843a11060000000000000000000000000000000000000000000000006f0000000100005847f80d000000000000000000000000000000000000000000000000000000030032be343b94f860124dc4fee278fdcbd38c102d883b08715b4403c792b8c7567edea634088bedcd7f60d9352b1f16c69830f3afd510b9afb67d2ec8b956f0e1dbc07eb79152904f3a7bf789fc869db56320adfe0901"), - ssz_receipt_bytes=bytes.fromhex("3a0000000852000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d01000001"), ), Test( + tx_profile=RlpLegacyTransaction, rlp_tx_hash=Hash32(bytes.fromhex("dc81918bf78322ce017c592e81c855f40bb96bd82da9779167de1de109962be6")), rlp_tx_bytes=bytes.fromhex("f88b822ecd8509839089a083015f909484654be796dad370032391d5479f8f1fd9ddd14e80a4d508e62389272d541e4168e5303b5838dcef5f9ac769a057f8dc6aabce7ec1e69b7ce5e625a078e88f9c69d217c76d92d5472f5812501021342f0054178c0579ee532dc2a218a0484723f0933633a6c213fc201ee3aecbe919579377b11a79acd887950a068e33"), - rlp_receipt_bytes=bytes.fromhex("f90109018301a93eb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0"), - ssz_tx_root=Root(bytes.fromhex("5004f2f523d0599fea4be4f933af406f7ade1d4973fe76dccf23b16c20789a55")), + ssz_tx_root=Hash32(bytes.fromhex("5004f2f523d0599fea4be4f933af406f7ade1d4973fe76dccf23b16c20789a55")), ssz_tx_bytes=bytes.fromhex("08000000a7000000ff000000000100000000000000cd2e00000000000055000000905f01000000000084654be796dad370032391d5479f8f1fd9ddd14e0000000000000000000000000000000000000000000000000000000000000000770000000100a089908309000000000000000000000000000000000000000000000000000000d508e62389272d541e4168e5303b5838dcef5f9ac769a057f8dc6aabce7ec1e69b7ce5e60300be49bd130e126a917ddb5fabf7cdeb6dd9887f4078e88f9c69d217c76d92d5472f5812501021342f0054178c0579ee532dc2a218484723f0933633a6c213fc201ee3aecbe919579377b11a79acd887950a068e3300"), - ssz_receipt_bytes=bytes.fromhex("3a0000002e05010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d01000001"), ), Test( + tx_profile=RlpAccessListTransaction, rlp_tx_hash=Hash32(bytes.fromhex("8135b5403ea5528341d661cdadd8eb67983909fc1644b0a133de708b13e10937")), rlp_tx_bytes=bytes.fromhex("01f90cc30182153680830bb224943765521db364ee269e9540970fd21e5a3e82569980b905845f53273d00000000000000000000000000000000000000000000000000112cfa39a81d7c00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000004e4128acb080000000000000000000000003765521db364ee269e9540970fd21e5a3e825699000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001dac7be33000000000000000000000000000000000000000000000000000000010005bd8200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006a9850e46518231b23e50467c975fa94026be5d5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000324128acb0800000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000001ade409ce94c21807e0000000000000000000000000000000000000000000000000000000010005bd8200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd855390000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd8553900000000000000000000000000000000000000000000000034a2e5498f6f66f80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4022c0d9f0000000000000000000000000000000000000000000001ade409ce94c21807e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a9850e46518231b23e50467c975fa94026be5d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f906d7f859941c86b3cdf2a60ae3a574f7f71d44e2c50bddb87ef842a00000000000000000000000000000000000000000000000000000000000000003a050f2c0a7453ed72f1987f5c26e34dd531d584edf35a9b2dd71d8cbd0b46cbec2f87a94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f863a0c5192a5360898ecb25d40688e79d4568e38430536a3f38f85b3859328d3cedbca0cc805915145ea1d9dd6fe22fe624a946d6b02968a5cf3e32ab5376b3fcedd207a0390f6178407c9b8e95802b8659e6df8e34c1e3d4f8d6a49e6132bbcdd937b63af7943765521db364ee269e9540970fd21e5a3e825699e1a00000000000000000000000000000000000000000000000000000000000000000f8fe94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f8e7a010d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390ba07050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3a01f21a62c4538bacf2aabeca410f0fe63151869f172e03c0e00357ba26a341effa00000000000000000000000000000000000000000000000000000000000000001a0faa1053f6d4d1d5c438dc7bcb1d301a860f75f57f936878518deaed1f60940d0a0390f6178407c9b8e95802b8659e6df8e34c1e3d4f8d6a49e6132bbcdd937b63aa0441b08c38c1e5e3510dc0c6fdeb4e6a8d60744b906171767ae804339d85b866cf89b946a9850e46518231b23e50467c975fa94026be5d5f884a0918cfc45073e7a8befeda107cec8f3ce514f4a406e227c253b570e1d6485d524a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000001f79457ab1ec28d129707052df4df418d58a2d46d5f51e1a00000000000000000000000000000000000000000000000000000000000000002f87a9405a9cbe762b36632b3594da4f082340e0e5343e8f863a0faa1053f6d4d1d5c438dc7bcb1d301a860f75f57f936878518deaed1f60940d0a0c5192a5360898ecb25d40688e79d4568e38430536a3f38f85b3859328d3cedbca00000000000000000000000000000000000000000000000000000000000000002f85994613c773c7a1d85d2f1dcc051b0573d33470762ebf842a00563a8a19823933e751ef690567f0351d13ee18500841743a77290b3deeac37da041feecc8dc55520132a464384eb4cad04fca8408899b069cf80a59042ac84c7af85994c757acba3c0506218b3022266a9dc7f3612d85f5f842a0ad77bf801726b2c83e9e3fa10f319bf2df99397a561126e8c3df0f7596519f75a0f0afdce5671e49e66c5829c89ac80a06875a30b8a123df04dc6cc02b9c7c845cf8dd94f1f85b2c54a2bd284b1cf4141d64fd171bd85539f8c6a00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000aa0000000000000000000000000000000000000000000000000000000000000000cd6940000000000000000000000000000000000000000c0f89b9488e6a0c2ddd26feeb64f039a2c41296fcb3f5640f884a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004a00000000000000000000000000000000000000000000000000000000000000001a0a6172f64e80168333d3bc97ef096a7cb251d24be47156dff7a40f6163a6ab42bd694a2327a938febf5fec13bacfb16ae10ecbc4cbdcfc0f8dd944d8dbd193d89b7b506be5dc9db75b91da00d6a1df8c6a00000000000000000000000000000000000000000000000000000000000000004a0b79e191a25a1c10448c48948add5400e67bdba9b68cb8e4ab5ccc4025afe7bf6a0000000000000000000000000000000000000000000000000000000000000000ba0d8f0dca3c14b74279ad90a75338db7cccdd5b2448369aeb32a94693a1c4cde0da00000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000000000000000000000000000000000000000002f794545973f28950f50fc6c7f52aab4ad214a27c0564e1a097176f14e7115c17104cb26360d789269f7e452d9b8ac6a3b8945c07081b33ac01a0dc6b057ac2591f402a243c3b81e429e750442d0a86f0fc112cf2eaaac26d4b8da03e5cace679d3104fae7f63ef0e64e7f4be5cfae64f9e03aebc0e19e5de0f29f8"), - rlp_receipt_bytes=bytes.fromhex("01f907360183064f13b901000020000001000000000020008000000000000000000000000000000004000000000000000000000000000800000800000a0000000800200000000000400000000000080000100008080000080010002000000000000000000000010000000000000000000000000000000000000000000000000000000000000000100008000000000000000000000000000000000000000000000100000800000040000000000000000000002010000000000000000000000000000000000020000000080000000000020000000000000000000000000008000000000010000000000000000000002800000004000000100000000000000000000420008000000a0000000000f9062bf89b94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640a00000000000000000000000003765521db364ee269e9540970fd21e5a3e825699a000000000000000000000000000000000000000000000000034b819a76c9101ddf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006a9850e46518231b23e50467c975fa94026be5d5a000000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640a000000000000000000000000000000000000000000000000000000001dac7be33f89b94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000003765521db364ee269e9540970fd21e5a3e825699a0000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd85539a000000000000000000000000000000000000000000000000034a2e5498f6f66f8f89b9457ab1ec28d129707052df4df418d58a2d46d5f51f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd85539a00000000000000000000000006a9850e46518231b23e50467c975fa94026be5d5a00000000000000000000000000000000000000000000001ade409ce94c21807e0f87994f1f85b2c54a2bd284b1cf4141d64fd171bd85539e1a01c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1b8400000000000000000000000000000000000000000000444ae3b74db3b9d4e6c6800000000000000000000000000000000000000000000008597e1b00a2ca3cb8bf8fc94f1f85b2c54a2bd284b1cf4141d64fd171bd85539f863a0d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822a00000000000000000000000003765521db364ee269e9540970fd21e5a3e825699a00000000000000000000000006a9850e46518231b23e50467c975fa94026be5d5b880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034a2e5498f6f66f80000000000000000000000000000000000000000000001ade409ce94c21807e00000000000000000000000000000000000000000000000000000000000000000f9011c946a9850e46518231b23e50467c975fa94026be5d5f863a0c42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67a00000000000000000000000003765521db364ee269e9540970fd21e5a3e825699a000000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640b8a00000000000000000000000000000000000000000000001ade409ce94c21807e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffe253841cd0000000000000000000000000000000000000000000010d1979907b2b7b44fb8000000000000000000000000000000000000000000000020160626e11f50affdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8cdf9011c9488e6a0c2ddd26feeb64f039a2c41296fcb3f5640f863a0c42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67a00000000000000000000000003765521db364ee269e9540970fd21e5a3e825699a00000000000000000000000003765521db364ee269e9540970fd21e5a3e825699b8a000000000000000000000000000000000000000000000000000000001dac7be33ffffffffffffffffffffffffffffffffffffffffffffffffcb47e658936efe23000000000000000000000000000000000000555373cbb17fb17a13909e0f3a3b00000000000000000000000000000000000000000000000066d5e9eea910e5ef0000000000000000000000000000000000000000000000000000000000030ca3"), - ssz_tx_root=Root(bytes.fromhex("5f31e697f90e2898f50d956a2c555098936956da4fc99e699b81836aa467c444")), + ssz_tx_root=Hash32(bytes.fromhex("5f31e697f90e2898f50d956a2c555098936956da4fc99e699b81836aa467c444")), ssz_tx_bytes=bytes.fromhex("08000000ef0c0000ff01000001010000000000000036150000000000005900000024b20b00000000003765521db364ee269e9540970fd21e5a3e82569900000000000000000000000000000000000000000000000000000000000000007b000000ff050000010000000000000000000000000000000000000000000000000000000000000000005f53273d00000000000000000000000000000000000000000000000000112cfa39a81d7c00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000004e4128acb080000000000000000000000003765521db364ee269e9540970fd21e5a3e825699000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001dac7be33000000000000000000000000000000000000000000000000000000010005bd8200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006a9850e46518231b23e50467c975fa94026be5d5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000324128acb0800000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000001ade409ce94c21807e0000000000000000000000000000000000000000000000000000000010005bd8200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd855390000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd8553900000000000000000000000000000000000000000000000034a2e5498f6f66f80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4022c0d9f0000000000000000000000000000000000000000000001ade409ce94c21807e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a9850e46518231b23e50467c975fa94026be5d5000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c000000940000000c010000440100003c020000d40200000c03000084030000dc030000340400000c05000024050000bc050000d4050000ac0600001c86b3cdf2a60ae3a574f7f71d44e2c50bddb87e18000000000000000000000000000000000000000000000000000000000000000000000350f2c0a7453ed72f1987f5c26e34dd531d584edf35a9b2dd71d8cbd0b46cbec2c02aaa39b223fe8d0a0e5c4f27ead9083c756cc218000000c5192a5360898ecb25d40688e79d4568e38430536a3f38f85b3859328d3cedbccc805915145ea1d9dd6fe22fe624a946d6b02968a5cf3e32ab5376b3fcedd207390f6178407c9b8e95802b8659e6df8e34c1e3d4f8d6a49e6132bbcdd937b63a3765521db364ee269e9540970fd21e5a3e825699180000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481800000010d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c31f21a62c4538bacf2aabeca410f0fe63151869f172e03c0e00357ba26a341eff0000000000000000000000000000000000000000000000000000000000000001faa1053f6d4d1d5c438dc7bcb1d301a860f75f57f936878518deaed1f60940d0390f6178407c9b8e95802b8659e6df8e34c1e3d4f8d6a49e6132bbcdd937b63a441b08c38c1e5e3510dc0c6fdeb4e6a8d60744b906171767ae804339d85b866c6a9850e46518231b23e50467c975fa94026be5d518000000918cfc45073e7a8befeda107cec8f3ce514f4a406e227c253b570e1d6485d52400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000157ab1ec28d129707052df4df418d58a2d46d5f5118000000000000000000000000000000000000000000000000000000000000000000000205a9cbe762b36632b3594da4f082340e0e5343e818000000faa1053f6d4d1d5c438dc7bcb1d301a860f75f57f936878518deaed1f60940d0c5192a5360898ecb25d40688e79d4568e38430536a3f38f85b3859328d3cedbc0000000000000000000000000000000000000000000000000000000000000002613c773c7a1d85d2f1dcc051b0573d33470762eb180000000563a8a19823933e751ef690567f0351d13ee18500841743a77290b3deeac37d41feecc8dc55520132a464384eb4cad04fca8408899b069cf80a59042ac84c7ac757acba3c0506218b3022266a9dc7f3612d85f518000000ad77bf801726b2c83e9e3fa10f319bf2df99397a561126e8c3df0f7596519f75f0afdce5671e49e66c5829c89ac80a06875a30b8a123df04dc6cc02b9c7c845cf1f85b2c54a2bd284b1cf4141d64fd171bd85539180000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000001800000088e6a0c2ddd26feeb64f039a2c41296fcb3f564018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001a6172f64e80168333d3bc97ef096a7cb251d24be47156dff7a40f6163a6ab42ba2327a938febf5fec13bacfb16ae10ecbc4cbdcf180000004d8dbd193d89b7b506be5dc9db75b91da00d6a1d180000000000000000000000000000000000000000000000000000000000000000000004b79e191a25a1c10448c48948add5400e67bdba9b68cb8e4ab5ccc4025afe7bf6000000000000000000000000000000000000000000000000000000000000000bd8f0dca3c14b74279ad90a75338db7cccdd5b2448369aeb32a94693a1c4cde0d00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000002545973f28950f50fc6c7f52aab4ad214a27c05641800000097176f14e7115c17104cb26360d789269f7e452d9b8ac6a3b8945c07081b33ac03001fd34033240c95aabf73e186a94b9576c6dab81bdc6b057ac2591f402a243c3b81e429e750442d0a86f0fc112cf2eaaac26d4b8d3e5cace679d3104fae7f63ef0e64e7f4be5cfae64f9e03aebc0e19e5de0f29f801"), - ssz_receipt_bytes=bytes.fromhex("3a000000d5a50400000000000020000001000000000020008000000000000000000000000000000004000000000000000000000000000800000800000a0000000800200000000000400000000000080000100008080000080010002000000000000000000000010000000000000000000000000000000000000000000000000000000000000000100008000000000000000000000000000000000000000000000100000800000040000000000000000000002010000000000000000000000000000000000020000000080000000000020000000000000000000000000008000000000010000000000000000000002800000004000000100000000000000000000420008000000a00000000000d0100000120000000bc00000058010000f4010000900200000c0300000804000024050000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21c0000007c000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f56400000000000000000000000003765521db364ee269e9540970fd21e5a3e82569900000000000000000000000000000000000000000000000034b819a76c9101dda0b86991c6218b36c1d19d4a2e9eb0ce3606eb481c0000007c000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef0000000000000000000000006a9850e46518231b23e50467c975fa94026be5d500000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000000000000000000001dac7be33c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21c0000007c000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef0000000000000000000000003765521db364ee269e9540970fd21e5a3e825699000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd8553900000000000000000000000000000000000000000000000034a2e5498f6f66f857ab1ec28d129707052df4df418d58a2d46d5f511c0000007c000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000f1f85b2c54a2bd284b1cf4141d64fd171bd855390000000000000000000000006a9850e46518231b23e50467c975fa94026be5d50000000000000000000000000000000000000000000001ade409ce94c21807e0f1f85b2c54a2bd284b1cf4141d64fd171bd855391c0000003c0000001c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad10000000000000000000000000000000000000000000444ae3b74db3b9d4e6c6800000000000000000000000000000000000000000000008597e1b00a2ca3cb8bf1f85b2c54a2bd284b1cf4141d64fd171bd855391c0000007c000000d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8220000000000000000000000003765521db364ee269e9540970fd21e5a3e8256990000000000000000000000006a9850e46518231b23e50467c975fa94026be5d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034a2e5498f6f66f80000000000000000000000000000000000000000000001ade409ce94c21807e000000000000000000000000000000000000000000000000000000000000000006a9850e46518231b23e50467c975fa94026be5d51c0000007c000000c42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca670000000000000000000000003765521db364ee269e9540970fd21e5a3e82569900000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f56400000000000000000000000000000000000000000000001ade409ce94c21807e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffe253841cd0000000000000000000000000000000000000000000010d1979907b2b7b44fb8000000000000000000000000000000000000000000000020160626e11f50affdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8cd88e6a0c2ddd26feeb64f039a2c41296fcb3f56401c0000007c000000c42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca670000000000000000000000003765521db364ee269e9540970fd21e5a3e8256990000000000000000000000003765521db364ee269e9540970fd21e5a3e82569900000000000000000000000000000000000000000000000000000001dac7be33ffffffffffffffffffffffffffffffffffffffffffffffffcb47e658936efe23000000000000000000000000000000000000555373cbb17fb17a13909e0f3a3b00000000000000000000000000000000000000000000000066d5e9eea910e5ef0000000000000000000000000000000000000000000000000000000000030ca3"), ), Test( + tx_profile=RlpFeeMarketTransaction, rlp_tx_hash=Hash32(bytes.fromhex("ba363483b992ef59342094ab98b8523ed6c055b5788e6726140d2badf27bf6d6")), rlp_tx_bytes=bytes.fromhex("02f9034c01830f9b358085064a2d5a958302690c946b75d8af000000e20b7a7ddf000ba900b4009a808403e168d79b2b2f1a397217ae1de4a6e543858b0191c9213aadbcc4ed256de6ecf902c0f85994c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f842a012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8a0f3bba710d3566d618899e2756f47b6b6ab971f4e7a9b49c8676839ce70a3b615f8dd94397217ae1de4a6e543858b0191c9213aadbcc4edf8c6a0000000000000000000000000000000000000000000000000000000000000000ca00000000000000000000000000000000000000000000000000000000000000008a00000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000009a0000000000000000000000000000000000000000000000000000000000000000af90183944ecfc56672c7630b84dac9c1f7407579715de155f9016ba0000000000000000000000000000000000000000000000000000000000000000fa038ed69781a961bb9622064044b9913b1581bddd02ed6468e0e8c3899ae4ff6cea029cb8bd4e192d16f51155329ce8b0f5eb88a1d9e4d3b93ce07efbac9e1c4d175a0a34640eb1c607d836ceb4af07c59befcec4cdb4943351c3a245f8712063aa3b6a0000000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000008a00e0b1ffc883156bcc50271d13adbf2142a3da019b453b028078482a0967df23ba0dc59cdc7b4ec63ea402af3d39d169ec1338c1dd00754c63deca3620ef11ce970a04eb8e6d369a44c627e68958caefca5b050389afd4410af55103da22160f32e6fa0e9c8ce3daf53241f9a1be37866116a52a57048d3c7f27faf9b4e8c6e2e50cf81a0489f94fa9c8ead25fac83530419e4f3ae96ec772b8179124ec3bf465ad8ddb2e01a0bcd30031cd0ee1132ec0fd4debd5157269adf0e478e4c4733d846b09f8891dcda02afb6af719e9b548c7d543e7698c5a9c15f97d7f126277d7178ff33670d84e08"), - rlp_receipt_bytes=bytes.fromhex("02f9045b018307ff02b9010000200000000000000000000080000000000000000000004000000000400000000000008000000020001000000000040002000000084000000000000000000000000000000000000000000008000000200000000040000000000000000000000000000200000000000000000000000000000000000000000080000010000000000000800000000000000000000000000000000000000000080000004000000000000000000000000000000000000000000000000000100000000000000000400000000002000000000000000000000000000004000000001000001000000000000000200000000000000000000000000000000000000000000000000000000000f90350f89b94c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80a0000000000000000000000000397217ae1de4a6e543858b0191c9213aadbcc4eda000000000000000000000000000000000000000000000000003e168d700000000f89b944ecfc56672c7630b84dac9c1f7407579715de155f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000397217ae1de4a6e543858b0191c9213aadbcc4eda00000000000000000000000004ecfc56672c7630b84dac9c1f7407579715de155a00000000000000000000000000000000000000000000001df1858999999999999f89b944ecfc56672c7630b84dac9c1f7407579715de155f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000397217ae1de4a6e543858b0191c9213aadbcc4eda00000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80a000000000000000000000000000000000000000000000238ece93666666666667f87994397217ae1de4a6e543858b0191c9213aadbcc4ede1a01c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1b8400000000000000000000000000000000000000000000ad652dd7967ecf01d441000000000000000000000000000000000000000000000000122a5b6292417bf7af8fc94397217ae1de4a6e543858b0191c9213aadbcc4edf863a0d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822a00000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80a00000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80b880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e168d70000000000000000000000000000000000000000000000000000256de6ec0000000000000000000000000000000000000000000000000000000000000000000000000000"), - ssz_tx_root=Root(bytes.fromhex("ddf3fdb24235f2df98b9c3b5444176ab135bf6240a821f12f18a75e1f7a46f86")), + ssz_tx_root=Hash32(bytes.fromhex("ddf3fdb24235f2df98b9c3b5444176ab135bf6240a821f12f18a75e1f7a46f86")), ssz_tx_bytes=bytes.fromhex("080000007c030000ff030000020100000000000000359b0f00000000005d0000000c690200000000006b75d8af000000e20b7a7ddf000ba900b4009a80d768e103000000000000000000000000000000000000000000000000000000007f0000009a0000004e0300000100955a2d4a060000000000000000000000000000000000000000000000000000002b2f1a397217ae1de4a6e543858b0191c9213aadbcc4ed256de6ec0c000000640000003c010000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21800000012231cd4c753cb5530a43a74c45106c24765e6f81dc8927d4f4be7e53315d5a8f3bba710d3566d618899e2756f47b6b6ab971f4e7a9b49c8676839ce70a3b615397217ae1de4a6e543858b0191c9213aadbcc4ed18000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a4ecfc56672c7630b84dac9c1f7407579715de15518000000000000000000000000000000000000000000000000000000000000000000000f38ed69781a961bb9622064044b9913b1581bddd02ed6468e0e8c3899ae4ff6ce29cb8bd4e192d16f51155329ce8b0f5eb88a1d9e4d3b93ce07efbac9e1c4d175a34640eb1c607d836ceb4af07c59befcec4cdb4943351c3a245f8712063aa3b6000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000080e0b1ffc883156bcc50271d13adbf2142a3da019b453b028078482a0967df23bdc59cdc7b4ec63ea402af3d39d169ec1338c1dd00754c63deca3620ef11ce9704eb8e6d369a44c627e68958caefca5b050389afd4410af55103da22160f32e6fe9c8ce3daf53241f9a1be37866116a52a57048d3c7f27faf9b4e8c6e2e50cf81489f94fa9c8ead25fac83530419e4f3ae96ec772b8179124ec3bf465ad8ddb2e010000000000000000000000000000000000000000000000000000000000000000000300ae2fc483527b8ef99eb5d9b44875f005ba1fae13bcd30031cd0ee1132ec0fd4debd5157269adf0e478e4c4733d846b09f8891dcd2afb6af719e9b548c7d543e7698c5a9c15f97d7f126277d7178ff33670d84e0801"), - ssz_receipt_bytes=bytes.fromhex("3a000000efaf010000000000002000000000000000000000800000000000000000000040000000004000000000000080000000200010000000000400020000000840000000000000000000000000000000000000000000080000002000000000400000000000000000000000000002000000000000000000000000000000000000000000800000100000000000008000000000000000000000000000000000000000000800000040000000000000000000000000000000000000000000000000001000000000000000004000000000020000000000000000000000000000040000000010000010000000000000002000000000000000000000000000000000000000000000000000000000000d0100000114000000b00000004c010000e801000064020000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21c0000007c000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef0000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80000000000000000000000000397217ae1de4a6e543858b0191c9213aadbcc4ed00000000000000000000000000000000000000000000000003e168d7000000004ecfc56672c7630b84dac9c1f7407579715de1551c0000007c000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000397217ae1de4a6e543858b0191c9213aadbcc4ed0000000000000000000000004ecfc56672c7630b84dac9c1f7407579715de1550000000000000000000000000000000000000000000001df18589999999999994ecfc56672c7630b84dac9c1f7407579715de1551c0000007c000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000397217ae1de4a6e543858b0191c9213aadbcc4ed0000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a8000000000000000000000000000000000000000000000238ece93666666666667397217ae1de4a6e543858b0191c9213aadbcc4ed1c0000003c0000001c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad10000000000000000000000000000000000000000000ad652dd7967ecf01d441000000000000000000000000000000000000000000000000122a5b6292417bf7a397217ae1de4a6e543858b0191c9213aadbcc4ed1c0000007c000000d78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8220000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a800000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e168d70000000000000000000000000000000000000000000000000000256de6ec0000000000000000000000000000000000000000000000000000000000000000000000000000"), ), Test( + tx_profile=RlpFeeMarketTransaction, rlp_tx_hash=Hash32(bytes.fromhex("a3b805acacb25da412a44bd9612a73464292fc684a400ab54f0a9626f7d9c3f2")), rlp_tx_bytes=bytes.fromhex("02f911d401038419fa53ad850c87eaa4da830efb7a8080b9117a608060405260405162000eda38038062000eda83398101604081905262000026916200049d565b828162000036828260006200004d565b50620000449050826200008a565b505050620005d0565b6200005883620000e5565b600082511180620000665750805b1562000085576200008383836200012760201b620001791760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000b562000156565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000e2816200018f565b50565b620000f08162000244565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200014f838360405180606001604052806027815260200162000eb360279139620002f8565b9392505050565b60006200018060008051602062000e9383398151915260001b6200037760201b620001a51760201c565b546001600160a01b0316919050565b6001600160a01b038116620001fa5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b806200022360008051602062000e9383398151915260001b6200037760201b620001a51760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6200025a816200037a60201b620001a81760201c565b620002be5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001f1565b80620002237f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200037760201b620001a51760201c565b6060600080856001600160a01b0316856040516200031791906200057d565b600060405180830381855af49150503d806000811462000354576040519150601f19603f3d011682016040523d82523d6000602084013e62000359565b606091505b5090925090506200036d8683838762000389565b9695505050505050565b90565b6001600160a01b03163b151590565b60608315620003fa578251620003f2576001600160a01b0385163b620003f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001f1565b508162000406565b6200040683836200040e565b949350505050565b8151156200041f5781518083602001fd5b8060405162461bcd60e51b8152600401620001f191906200059b565b80516001600160a01b03811681146200045357600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200048b57818101518382015260200162000471565b83811115620000835750506000910152565b600080600060608486031215620004b357600080fd5b620004be846200043b565b9250620004ce602085016200043b565b60408501519092506001600160401b0380821115620004ec57600080fd5b818601915086601f8301126200050157600080fd5b81518181111562000516576200051662000458565b604051601f8201601f19908116603f0116810190838211818310171562000541576200054162000458565b816040528281528960208487010111156200055b57600080fd5b6200056e8360208301602088016200046e565b80955050505050509250925092565b60008251620005918184602087016200046e565b9190910192915050565b6020815260008251806020840152620005bc8160408501602087016200046e565b601f01601f19169190910160400192915050565b6108b380620005e06000396000f3fe60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65640000000000000000000000007e22fcb742572515d1c3fef972ec066c995820ef000000000000000000000000d89f6892a2b58d50e0e8f51a961b12a25ce3f7570000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000020457405d050000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000064c7eb930000000000000000000000000000000000000000000000000000000064d2bde300000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000004580900be782a567ad407cc8fcde24dbda2a1aae000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000165a0bc00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000009795118749000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000023a8f4b6a00000000000000000000000000000000000000000000000000000000c080a06fd00841d705c002a846de1b56d0c36941cd2897a7bb19419d427a252bc4fff4a05be5ed4725f8b6047b5309da5f47d1e98fa2c79e5c0841595291fae7167de108"), - rlp_receipt_bytes=bytes.fromhex("02f90354018316fa7cb901000000000000000000000000000000000040000000000000000080000001000000000000000000000000000000000000000000000200004000000000000201000000000000000000000000000000000200000100000000000000000000000000000000000002000000000000000000080004000080000000000000000000000040000000000000000000000004000000000000000000008000000000040080000000000000000000000000000000040000000000000000000000000000000000000000002020000000000000000004000a000000000400000000000000000020000000000000000000000000000000000000000000000000000000000000020000f90249f85a94451445a9adb7e4c8ab4a266755626c136e093a4ef842a0bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3ba00000000000000000000000007e22fcb742572515d1c3fef972ec066c995820ef80f87b94451445a9adb7e4c8ab4a266755626c136e093a4ef863a08be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000979db18107552faa36a52480a1dbb65ed3f51d7080f89994451445a9adb7e4c8ab4a266755626c136e093a4ee1a023f6ad8232d75562dd1c6b37dfc895af6bfc1ecd0fb3b88722c6a5e6b4dc9a20b8600000000000000000000000000000000000000000000000000000000064c7eb930000000000000000000000000000000000000000000000000000000064d2bde30000000000000000000000000000000000000000000000000000000064c7e277f85894451445a9adb7e4c8ab4a266755626c136e093a4ee1a07f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498a00000000000000000000000000000000000000000000000000000000000000001f87994451445a9adb7e4c8ab4a266755626c136e093a4ee1a07e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798fb8400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d89f6892a2b58d50e0e8f51a961b12a25ce3f757"), - ssz_tx_root=Root(bytes.fromhex("1b7474a5d934e0bd725f35a6bdcb5b5e33b18c4cce6cf20706438a6bc707c2c7")), + ssz_tx_root=Hash32(bytes.fromhex("1b7474a5d934e0bd725f35a6bdcb5b5e33b18c4cce6cf20706438a6bc707c2c7")), ssz_tx_bytes=bytes.fromhex("0800000013120000df0300000201000000000000000300000000000000490000007afb0e000000000000000000000000000000000000000000000000000000000000000000000000006b000000e5110000e51100000100daa4ea870c000000000000000000000000000000000000000000000000000000608060405260405162000eda38038062000eda83398101604081905262000026916200049d565b828162000036828260006200004d565b50620000449050826200008a565b505050620005d0565b6200005883620000e5565b600082511180620000665750805b1562000085576200008383836200012760201b620001791760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000b562000156565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000e2816200018f565b50565b620000f08162000244565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200014f838360405180606001604052806027815260200162000eb360279139620002f8565b9392505050565b60006200018060008051602062000e9383398151915260001b6200037760201b620001a51760201c565b546001600160a01b0316919050565b6001600160a01b038116620001fa5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b806200022360008051602062000e9383398151915260001b6200037760201b620001a51760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6200025a816200037a60201b620001a81760201c565b620002be5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001f1565b80620002237f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200037760201b620001a51760201c565b6060600080856001600160a01b0316856040516200031791906200057d565b600060405180830381855af49150503d806000811462000354576040519150601f19603f3d011682016040523d82523d6000602084013e62000359565b606091505b5090925090506200036d8683838762000389565b9695505050505050565b90565b6001600160a01b03163b151590565b60608315620003fa578251620003f2576001600160a01b0385163b620003f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001f1565b508162000406565b6200040683836200040e565b949350505050565b8151156200041f5781518083602001fd5b8060405162461bcd60e51b8152600401620001f191906200059b565b80516001600160a01b03811681146200045357600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200048b57818101518382015260200162000471565b83811115620000835750506000910152565b600080600060608486031215620004b357600080fd5b620004be846200043b565b9250620004ce602085016200043b565b60408501519092506001600160401b0380821115620004ec57600080fd5b818601915086601f8301126200050157600080fd5b81518181111562000516576200051662000458565b604051601f8201601f19908116603f0116810190838211818310171562000541576200054162000458565b816040528281528960208487010111156200055b57600080fd5b6200056e8360208301602088016200046e565b80955050505050509250925092565b60008251620005918184602087016200046e565b9190910192915050565b6020815260008251806020840152620005bc8160408501602087016200046e565b601f01601f19169190910160400192915050565b6108b380620005e06000396000f3fe60806040523661001357610011610017565b005b6100115b61001f6101b7565b6001600160a01b0316336001600160a01b0316141561016f5760606001600160e01b031960003516631b2ce7f360e11b8114156100655761005e6101ea565b9150610167565b6001600160e01b0319811663278f794360e11b14156100865761005e610241565b6001600160e01b031981166308f2839760e41b14156100a75761005e610287565b6001600160e01b031981166303e1469160e61b14156100c85761005e6102b8565b6001600160e01b03198116635c60da1b60e01b14156100e95761005e6102f8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b61017761030c565b565b606061019e83836040518060600160405280602781526020016108576027913961031c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101f4610394565b600061020336600481846106a2565b81019061021091906106e8565b905061022d8160405180602001604052806000815250600061039f565b505060408051602081019091526000815290565b606060008061025336600481846106a2565b8101906102609190610719565b915091506102708282600161039f565b604051806020016040528060008152509250505090565b6060610291610394565b60006102a036600481846106a2565b8101906102ad91906106e8565b905061022d816103cb565b60606102c2610394565b60006102cc6101b7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b6060610302610394565b60006102cc610422565b610177610317610422565b610431565b6060600080856001600160a01b0316856040516103399190610807565b600060405180830381855af49150503d8060008114610374576040519150601f19603f3d011682016040523d82523d6000602084013e610379565b606091505b509150915061038a86838387610455565b9695505050505050565b341561017757600080fd5b6103a8836104d3565b6000825111806103b55750805b156103c6576103c48383610179565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103f46101b7565b604080516001600160a01b03928316815291841660208301520160405180910390a161041f81610513565b50565b600061042c6105bc565b905090565b3660008037600080366000845af43d6000803e808015610450573d6000f35b3d6000fd5b606083156104c15782516104ba576001600160a01b0385163b6104ba5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161015e565b50816104cb565b6104cb83836105e4565b949350505050565b6104dc8161060e565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105785760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161015e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101db565b8151156105f45781518083602001fd5b8060405162461bcd60e51b815260040161015e9190610823565b6001600160a01b0381163b61067b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161015e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61059b565b600080858511156106b257600080fd5b838611156106bf57600080fd5b5050820193919092039150565b80356001600160a01b03811681146106e357600080fd5b919050565b6000602082840312156106fa57600080fd5b61019e826106cc565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561072c57600080fd5b610735836106cc565b9150602083013567ffffffffffffffff8082111561075257600080fd5b818501915085601f83011261076657600080fd5b81358181111561077857610778610703565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610703565b816040528281528860208487010111156107b957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107f65781810151838201526020016107de565b838111156103c45750506000910152565b600082516108198184602087016107db565b9190910192915050565b60208152600082518060208401526108428160408501602087016107db565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122012bb4f564f73959a03513dc74fc3c6e40e8386e6f02c16b78d6db00ce0aa16af64736f6c63430008090033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65640000000000000000000000007e22fcb742572515d1c3fef972ec066c995820ef000000000000000000000000d89f6892a2b58d50e0e8f51a961b12a25ce3f7570000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000020457405d050000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000064c7eb930000000000000000000000000000000000000000000000000000000064d2bde300000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000004580900be782a567ad407cc8fcde24dbda2a1aae000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000165a0bc00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000009795118749000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000023a8f4b6a000000000000000000000000000000000000000000000000000000000100ad53fa19000000000000000000000000000000000000000000000000000000000300979db18107552faa36a52480a1dbb65ed3f51d706fd00841d705c002a846de1b56d0c36941cd2897a7bb19419d427a252bc4fff45be5ed4725f8b6047b5309da5f47d1e98fa2c79e5c0841595291fae7167de10800"), - ssz_receipt_bytes=bytes.fromhex("3e0000007afb0e0000000000451445a9adb7e4c8ab4a266755626c136e093a4e0000000000000000000000000000000040000000000000000080000001000000000000000000000000000000000000000000000200004000000000000201000000000000000000000000000000000200000100000000000000000000000000000000000002000000000000000000080004000080000000000000000000000040000000000000000000000004000000000000000000008000000000040080000000000000000000000000000000040000000000000000000000000000000000000000002020000000000000000004000a00000000040000000000000000002000000000000000000000000000000000000000000000000000000000000002000021010000011400000070000000ec00000088010000e4010000451445a9adb7e4c8ab4a266755626c136e093a4e1c0000005c000000bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b0000000000000000000000007e22fcb742572515d1c3fef972ec066c995820ef451445a9adb7e4c8ab4a266755626c136e093a4e1c0000007c0000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000979db18107552faa36a52480a1dbb65ed3f51d70451445a9adb7e4c8ab4a266755626c136e093a4e1c0000003c00000023f6ad8232d75562dd1c6b37dfc895af6bfc1ecd0fb3b88722c6a5e6b4dc9a200000000000000000000000000000000000000000000000000000000064c7eb930000000000000000000000000000000000000000000000000000000064d2bde30000000000000000000000000000000000000000000000000000000064c7e277451445a9adb7e4c8ab4a266755626c136e093a4e1c0000003c0000007f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024980000000000000000000000000000000000000000000000000000000000000001451445a9adb7e4c8ab4a266755626c136e093a4e1c0000003c0000007e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d89f6892a2b58d50e0e8f51a961b12a25ce3f757"), ), ] -transactions = [upgrade_rlp_transaction_to_ssz(test.rlp_tx_bytes) for test in tests] -receipts = upgrade_rlp_receipts_to_ssz([test.rlp_receipt_bytes for test in tests], transactions) +for test in tests: + tx = upgrade_rlp_transaction_to_ssz(test.rlp_tx_bytes) -for i in range(len(tests)): - validate_transaction(transactions[i]) - assert compute_tx_hash(transactions[i]) == tests[i].rlp_tx_hash - assert transactions[i].hash_tree_root() == tests[i].ssz_tx_root + validate_tx_from_address(tx) + assert compute_tx_hash(tx) == test.rlp_tx_hash + assert tx.hash_tree_root() == test.ssz_tx_root - stable_transaction = Transaction(backing=transactions[i].get_backing()) - assert stable_transaction.encode_bytes() == tests[i].ssz_tx_bytes - assert stable_transaction.hash_tree_root() == tests[i].ssz_tx_root - - stable_receipt = Receipt(backing=receipts[i].get_backing()) - assert stable_receipt.encode_bytes() == tests[i].ssz_receipt_bytes - -transactions_stable = [Transaction(backing=transaction.get_backing()) for transaction in transactions] -assert select_transaction_profile(transactions_stable[0]) is ReplayableTransaction -assert select_transaction_profile(transactions_stable[1]) is ReplayableTransaction -assert select_transaction_profile(transactions_stable[2]) is LegacyTransaction -assert select_transaction_profile(transactions_stable[3]) is Eip2930Transaction -assert select_transaction_profile(transactions_stable[4]) is Eip1559Transaction -assert select_transaction_profile(transactions_stable[5]) is Eip1559Transaction - -receipts_stable = [Receipt(backing=receipt.get_backing()) for receipt in receipts] -assert select_receipt_profile(receipts_stable[0]) is HomesteadReceipt -assert select_receipt_profile(receipts_stable[1]) is BasicReceipt -assert select_receipt_profile(receipts_stable[2]) is BasicReceipt -assert select_receipt_profile(receipts_stable[3]) is BasicReceipt -assert select_receipt_profile(receipts_stable[4]) is BasicReceipt -assert select_receipt_profile(receipts_stable[5]) is BasicReceipt + stable_tx = Transaction(backing=tx.get_backing()) + assert identify_transaction_profile(stable_tx) is test.tx_profile + assert stable_tx.hash_tree_root() == test.ssz_tx_root + assert stable_tx.encode_bytes() == test.ssz_tx_bytes diff --git a/assets/eip-6493/rlp_types.py b/assets/eip-6404/rlp_types.py similarity index 61% rename from assets/eip-6493/rlp_types.py rename to assets/eip-6404/rlp_types.py index 7bce442125e8e..4c219b959feab 100644 --- a/assets/eip-6493/rlp_types.py +++ b/assets/eip-6404/rlp_types.py @@ -9,8 +9,8 @@ class Hash32(Bytes32): class LegacyRlpTransactionPayload(Serializable): fields = ( ('nonce', big_endian_int), - ('gasprice', big_endian_int), - ('startgas', big_endian_int), + ('gas_price', big_endian_int), + ('gas', big_endian_int), ('to', Binary(20, 20, allow_empty=True)), ('value', big_endian_int), ('data', binary), @@ -19,8 +19,8 @@ class LegacyRlpTransactionPayload(Serializable): class LegacyRlpTransaction(Serializable): fields = ( ('nonce', big_endian_int), - ('gasprice', big_endian_int), - ('startgas', big_endian_int), + ('gas_price', big_endian_int), + ('gas', big_endian_int), ('to', Binary(20, 20, allow_empty=True)), ('value', big_endian_int), ('data', binary), @@ -33,8 +33,8 @@ def compute_legacy_sig_hash(tx: LegacyRlpTransaction) -> Hash32: if tx.v not in (27, 28): # EIP-155 return Hash32(keccak(encode(LegacyRlpTransaction( nonce=tx.nonce, - gasprice=tx.gasprice, - startgas=tx.startgas, + gas_price=tx.gas_price, + gas=tx.gas, to=tx.to, value=tx.value, data=tx.data, @@ -45,8 +45,8 @@ def compute_legacy_sig_hash(tx: LegacyRlpTransaction) -> Hash32: else: return Hash32(keccak(encode(LegacyRlpTransactionPayload( nonce=tx.nonce, - gasprice=tx.gasprice, - startgas=tx.startgas, + gas_price=tx.gas_price, + gas=tx.gas, to=tx.to, value=tx.value, data=tx.data, @@ -55,63 +55,63 @@ def compute_legacy_sig_hash(tx: LegacyRlpTransaction) -> Hash32: def compute_legacy_tx_hash(tx: LegacyRlpTransaction) -> Hash32: return Hash32(keccak(encode(tx))) -class Eip2930RlpTransactionPayload(Serializable): +class AccessListRlpTransactionPayload(Serializable): fields = ( - ('chainId', big_endian_int), + ('chain_id', big_endian_int), ('nonce', big_endian_int), - ('gasPrice', big_endian_int), - ('gasLimit', big_endian_int), + ('gas_price', big_endian_int), + ('gas', big_endian_int), ('to', Binary(20, 20, allow_empty=True)), ('value', big_endian_int), ('data', binary), - ('accessList', CountableList(RLPList([ + ('access_list', CountableList(RLPList([ Binary(20, 20), CountableList(Binary(32, 32)), ]))), ) -class Eip2930RlpTransaction(Serializable): +class AccessListRlpTransaction(Serializable): fields = ( - ('chainId', big_endian_int), + ('chain_id', big_endian_int), ('nonce', big_endian_int), - ('gasPrice', big_endian_int), - ('gasLimit', big_endian_int), + ('gas_price', big_endian_int), + ('gas', big_endian_int), ('to', Binary(20, 20, allow_empty=True)), ('value', big_endian_int), ('data', binary), - ('accessList', CountableList(RLPList([ + ('access_list', CountableList(RLPList([ Binary(20, 20), CountableList(Binary(32, 32)), ]))), - ('signatureYParity', big_endian_int), - ('signatureR', big_endian_int), - ('signatureS', big_endian_int), + ('y_parity', big_endian_int), + ('r', big_endian_int), + ('s', big_endian_int), ) -def compute_eip2930_sig_hash(tx: Eip2930RlpTransaction) -> Hash32: - return Hash32(keccak(bytes([0x01]) + encode(Eip2930RlpTransactionPayload( - chainId=tx.chainId, +def compute_access_list_sig_hash(tx: AccessListRlpTransaction) -> Hash32: + return Hash32(keccak(bytes([0x01]) + encode(AccessListRlpTransactionPayload( + chain_id=tx.chain_id, nonce=tx.nonce, - gasPrice=tx.gasPrice, - gasLimit=tx.gasLimit, + gas_price=tx.gas_price, + gas=tx.gas, to=tx.to, value=tx.value, data=tx.data, - accessList=tx.accessList, + access_list=tx.access_list, )))) -def compute_eip2930_tx_hash(tx: Eip2930RlpTransaction) -> Hash32: +def compute_access_list_tx_hash(tx: AccessListRlpTransaction) -> Hash32: return Hash32(keccak(bytes([0x01]) + encode(tx))) -class Eip1559RlpTransactionPayload(Serializable): +class FeeMarketRlpTransactionPayload(Serializable): fields = ( ('chain_id', big_endian_int), ('nonce', big_endian_int), ('max_priority_fee_per_gas', big_endian_int), ('max_fee_per_gas', big_endian_int), - ('gas_limit', big_endian_int), - ('destination', Binary(20, 20, allow_empty=True)), - ('amount', big_endian_int), + ('gas', big_endian_int), + ('to', Binary(20, 20, allow_empty=True)), + ('value', big_endian_int), ('data', binary), ('access_list', CountableList(RLPList([ Binary(20, 20), @@ -119,48 +119,48 @@ class Eip1559RlpTransactionPayload(Serializable): ]))), ) -class Eip1559RlpTransaction(Serializable): +class FeeMarketRlpTransaction(Serializable): fields = ( ('chain_id', big_endian_int), ('nonce', big_endian_int), ('max_priority_fee_per_gas', big_endian_int), ('max_fee_per_gas', big_endian_int), - ('gas_limit', big_endian_int), - ('destination', Binary(20, 20, allow_empty=True)), - ('amount', big_endian_int), + ('gas', big_endian_int), + ('to', Binary(20, 20, allow_empty=True)), + ('value', big_endian_int), ('data', binary), ('access_list', CountableList(RLPList([ Binary(20, 20), CountableList(Binary(32, 32)), ]))), - ('signature_y_parity', big_endian_int), - ('signature_r', big_endian_int), - ('signature_s', big_endian_int), + ('y_parity', big_endian_int), + ('r', big_endian_int), + ('s', big_endian_int), ) -def compute_eip1559_sig_hash(tx: Eip1559RlpTransaction) -> Hash32: - return Hash32(keccak(bytes([0x02]) + encode(Eip1559RlpTransactionPayload( +def compute_fee_market_sig_hash(tx: FeeMarketRlpTransaction) -> Hash32: + return Hash32(keccak(bytes([0x02]) + encode(FeeMarketRlpTransactionPayload( chain_id=tx.chain_id, nonce=tx.nonce, max_priority_fee_per_gas=tx.max_priority_fee_per_gas, max_fee_per_gas=tx.max_fee_per_gas, - gas_limit=tx.gas_limit, - destination=tx.destination, - amount=tx.amount, + gas=tx.gas, + to=tx.to, + value=tx.value, data=tx.data, access_list=tx.access_list, )))) -def compute_eip1559_tx_hash(tx: Eip1559RlpTransaction) -> Hash32: +def compute_fee_market_tx_hash(tx: FeeMarketRlpTransaction) -> Hash32: return Hash32(keccak(bytes([0x02]) + encode(tx))) -class Eip4844RlpTransactionPayload(Serializable): +class BlobRlpTransactionPayload(Serializable): fields = ( ('chain_id', big_endian_int), ('nonce', big_endian_int), ('max_priority_fee_per_gas', big_endian_int), ('max_fee_per_gas', big_endian_int), - ('gas_limit', big_endian_int), + ('gas', big_endian_int), ('to', Binary(20, 20)), ('value', big_endian_int), ('data', binary), @@ -172,13 +172,13 @@ class Eip4844RlpTransactionPayload(Serializable): ('blob_versioned_hashes', CountableList(Binary(32, 32))), ) -class Eip4844RlpTransaction(Serializable): +class BlobRlpTransaction(Serializable): fields = ( ('chain_id', big_endian_int), ('nonce', big_endian_int), ('max_priority_fee_per_gas', big_endian_int), ('max_fee_per_gas', big_endian_int), - ('gas_limit', big_endian_int), + ('gas', big_endian_int), ('to', Binary(20, 20)), ('value', big_endian_int), ('data', binary), @@ -188,18 +188,18 @@ class Eip4844RlpTransaction(Serializable): ]))), ('max_fee_per_blob_gas', big_endian_int), ('blob_versioned_hashes', CountableList(Binary(32, 32))), - ('signature_y_parity', big_endian_int), - ('signature_r', big_endian_int), - ('signature_s', big_endian_int), + ('y_parity', big_endian_int), + ('r', big_endian_int), + ('s', big_endian_int), ) -def compute_eip4844_sig_hash(tx: Eip4844RlpTransaction) -> Hash32: - return Hash32(keccak(bytes([0x03]) + encode(Eip4844RlpTransactionPayload( +def compute_blob_sig_hash(tx: BlobRlpTransaction) -> Hash32: + return Hash32(keccak(bytes([0x03]) + encode(BlobRlpTransactionPayload( chain_id=tx.chain_id, nonce=tx.nonce, max_priority_fee_per_gas=tx.max_priority_fee_per_gas, max_fee_per_gas=tx.max_fee_per_gas, - gas_limit=tx.gas_limit, + gas=tx.gas, to=tx.to, value=tx.value, data=tx.data, @@ -208,17 +208,5 @@ def compute_eip4844_sig_hash(tx: Eip4844RlpTransaction) -> Hash32: blob_versioned_hashes=tx.blob_versioned_hashes, )))) -def compute_eip4844_tx_hash(tx: Eip4844RlpTransaction) -> Hash32: +def compute_blob_tx_hash(tx: BlobRlpTransaction) -> Hash32: return Hash32(keccak(bytes([0x03]) + encode(tx))) - -class RlpReceipt(Serializable): - fields = ( - ('post_state_or_status', Binary(0, 32)), - ('cumulative_gas_used', big_endian_int), - ('logs_bloom', Binary(256, 256)), - ('logs', CountableList(RLPList([ - Binary(20, 20), - CountableList(Binary(32, 32), 4), - binary, - ]))), - ) diff --git a/assets/eip-6493/ssz_types.py b/assets/eip-6404/ssz_types.py similarity index 55% rename from assets/eip-6493/ssz_types.py rename to assets/eip-6404/ssz_types.py index 150dac235f73c..db6abfe0a82dd 100644 --- a/assets/eip-6493/ssz_types.py +++ b/assets/eip-6404/ssz_types.py @@ -1,47 +1,73 @@ -from os import path as os_path -from sys import path -current_dir = os_path.dirname(os_path.realpath(__file__)) -path.append(current_dir) -path.append(current_dir + '/../eip-7495') - from typing import Optional, Type from eth_hash.auto import keccak -from remerkleable.basic import boolean, uint8, uint64, uint256 -from remerkleable.byte_arrays import ByteList, ByteVector, Bytes4, Bytes32 +from remerkleable.basic import uint8, uint64, uint256 +from remerkleable.byte_arrays import ByteList, ByteVector, Bytes32 from remerkleable.complex import Container, List -from rlp_types import Hash32 +from remerkleable.stable_container import Profile, StableContainer from secp256k1 import ECDSA, PublicKey -from stable_container import Profile, StableContainer -class TransactionType(uint8): +class Hash32(Bytes32): pass -TRANSACTION_TYPE_LEGACY = TransactionType(0x00) -TRANSACTION_TYPE_EIP2930 = TransactionType(0x01) -TRANSACTION_TYPE_EIP1559 = TransactionType(0x02) -TRANSACTION_TYPE_EIP4844 = TransactionType(0x03) -TRANSACTION_TYPE_SSZ = TransactionType(0x04) - class ExecutionAddress(ByteVector[20]): pass class VersionedHash(Bytes32): pass +ECDSA_SIGNATURE_SIZE = 32 + 32 + 1 +MAX_EXECUTION_SIGNATURE_FIELDS = uint64(2**4) + +class ExecutionSignature(StableContainer[MAX_EXECUTION_SIGNATURE_FIELDS]): + from_: Optional[ExecutionAddress] + ecdsa_signature: Optional[ByteVector[ECDSA_SIGNATURE_SIZE]] + +class EcdsaExecutionSignature(Profile[ExecutionSignature]): + from_: ExecutionAddress + ecdsa_signature: ByteVector[ECDSA_SIGNATURE_SIZE] + +def ecdsa_pack_signature(y_parity: bool, + r: uint256, + s: uint256) -> ByteVector[ECDSA_SIGNATURE_SIZE]: + return r.to_bytes(32, 'big') + s.to_bytes(32, 'big') + bytes([0x01 if y_parity else 0x00]) + +def ecdsa_unpack_signature(signature: ByteVector[ECDSA_SIGNATURE_SIZE]) -> tuple[bool, uint256, uint256]: + y_parity = signature[64] != 0 + r = uint256.from_bytes(signature[0:32], 'big') + s = uint256.from_bytes(signature[32:64], 'big') + return (y_parity, r, s) + +def ecdsa_validate_signature(signature: ByteVector[ECDSA_SIGNATURE_SIZE]): + SECP256K1N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 + assert len(signature) == 65 + assert signature[64] in (0, 1) + _, r, s = ecdsa_unpack_signature(signature) + assert 0 < r < SECP256K1N + assert 0 < s <= SECP256K1N // 2 + +def ecdsa_recover_from_address(signature: ByteVector[ECDSA_SIGNATURE_SIZE], + sig_hash: Hash32) -> ExecutionAddress: + ecdsa = ECDSA() + recover_sig = ecdsa.ecdsa_recoverable_deserialize(signature[0:64], signature[64]) + public_key = PublicKey(ecdsa.ecdsa_recover(sig_hash, recover_sig, raw=True)) + uncompressed = public_key.serialize(compressed=False) + return ExecutionAddress(keccak(uncompressed[1:])[12:]) + +class TransactionType(uint8): + pass + class ChainId(uint64): pass class FeePerGas(uint256): pass +MAX_FEES_PER_GAS_FIELDS = uint64(2**4) MAX_CALLDATA_SIZE = uint64(2**24) MAX_ACCESS_LIST_STORAGE_KEYS = uint64(2**19) MAX_ACCESS_LIST_SIZE = uint64(2**19) MAX_BLOB_COMMITMENTS_PER_BLOCK = uint64(2**12) -ECDSA_SIGNATURE_SIZE = 32 + 32 + 1 -MAX_FEES_PER_GAS_FIELDS = uint64(2**4) MAX_TRANSACTION_PAYLOAD_FIELDS = uint64(2**5) -MAX_TRANSACTION_SIGNATURE_FIELDS = uint64(2**4) class FeesPerGas(StableContainer[MAX_FEES_PER_GAS_FIELDS]): regular: Optional[FeePerGas] @@ -76,13 +102,9 @@ class TransactionPayload(StableContainer[MAX_TRANSACTION_PAYLOAD_FIELDS]): # EIP-4844 blob_versioned_hashes: Optional[List[VersionedHash, MAX_BLOB_COMMITMENTS_PER_BLOCK]] -class TransactionSignature(StableContainer[MAX_TRANSACTION_SIGNATURE_FIELDS]): - from_: Optional[ExecutionAddress] - ecdsa_signature: Optional[ByteVector[ECDSA_SIGNATURE_SIZE]] - class Transaction(Container): payload: TransactionPayload - signature: TransactionSignature + signature: ExecutionSignature class BasicFeesPerGas(Profile[FeesPerGas]): regular: FeePerGas @@ -91,53 +113,52 @@ class BlobFeesPerGas(Profile[FeesPerGas]): regular: FeePerGas blob: FeePerGas -class EcdsaTransactionSignature(Profile[TransactionSignature]): - from_: ExecutionAddress - ecdsa_signature: ByteVector[ECDSA_SIGNATURE_SIZE] - -class ReplayableTransactionPayload(Profile[TransactionPayload]): - type_: TransactionType +class BasicTransactionPayload(Profile[TransactionPayload]): + chain_id: ChainId nonce: uint64 max_fees_per_gas: BasicFeesPerGas gas: uint64 to: Optional[ExecutionAddress] value: uint256 input_: ByteList[MAX_CALLDATA_SIZE] + access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] + max_priority_fees_per_gas: BasicFeesPerGas -class ReplayableTransaction(Container): - payload: ReplayableTransactionPayload - signature: EcdsaTransactionSignature +class BasicTransaction(Container): + payload: BasicTransactionPayload + signature: EcdsaExecutionSignature -class LegacyTransactionPayload(Profile[TransactionPayload]): - type_: TransactionType +class BlobTransactionPayload(Profile[TransactionPayload]): chain_id: ChainId nonce: uint64 - max_fees_per_gas: BasicFeesPerGas + max_fees_per_gas: BlobFeesPerGas gas: uint64 - to: Optional[ExecutionAddress] + to: ExecutionAddress value: uint256 input_: ByteList[MAX_CALLDATA_SIZE] + access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] + max_priority_fees_per_gas: BlobFeesPerGas + blob_versioned_hashes: List[VersionedHash, MAX_BLOB_COMMITMENTS_PER_BLOCK] -class LegacyTransaction(Container): - payload: LegacyTransactionPayload - signature: EcdsaTransactionSignature +class BlobTransaction(Container): + payload: BlobTransactionPayload + signature: EcdsaExecutionSignature -class Eip2930TransactionPayload(Profile[TransactionPayload]): +class RlpLegacyTransactionPayload(Profile[TransactionPayload]): type_: TransactionType - chain_id: ChainId + chain_id: Optional[ChainId] nonce: uint64 max_fees_per_gas: BasicFeesPerGas gas: uint64 to: Optional[ExecutionAddress] value: uint256 input_: ByteList[MAX_CALLDATA_SIZE] - access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] -class Eip2930Transaction(Container): - payload: Eip2930TransactionPayload - signature: EcdsaTransactionSignature +class RlpLegacyTransaction(Container): + payload: RlpLegacyTransactionPayload + signature: EcdsaExecutionSignature -class Eip1559TransactionPayload(Profile[TransactionPayload]): +class RlpAccessListTransactionPayload(Profile[TransactionPayload]): type_: TransactionType chain_id: ChainId nonce: uint64 @@ -147,30 +168,13 @@ class Eip1559TransactionPayload(Profile[TransactionPayload]): value: uint256 input_: ByteList[MAX_CALLDATA_SIZE] access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] - max_priority_fees_per_gas: BasicFeesPerGas -class Eip1559Transaction(Container): - payload: Eip1559TransactionPayload - signature: EcdsaTransactionSignature +class RlpAccessListTransaction(Container): + payload: RlpAccessListTransactionPayload + signature: EcdsaExecutionSignature -class Eip4844TransactionPayload(Profile[TransactionPayload]): +class RlpFeeMarketTransactionPayload(Profile[TransactionPayload]): type_: TransactionType - chain_id: ChainId - nonce: uint64 - max_fees_per_gas: BlobFeesPerGas - gas: uint64 - to: ExecutionAddress - value: uint256 - input_: ByteList[MAX_CALLDATA_SIZE] - access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] - max_priority_fees_per_gas: BlobFeesPerGas - blob_versioned_hashes: List[VersionedHash, MAX_BLOB_COMMITMENTS_PER_BLOCK] - -class Eip4844Transaction(Container): - payload: Eip4844TransactionPayload - signature: EcdsaTransactionSignature - -class BasicTransactionPayload(Profile[TransactionPayload]): chain_id: ChainId nonce: uint64 max_fees_per_gas: BasicFeesPerGas @@ -181,11 +185,12 @@ class BasicTransactionPayload(Profile[TransactionPayload]): access_list: List[AccessTuple, MAX_ACCESS_LIST_SIZE] max_priority_fees_per_gas: BasicFeesPerGas -class BasicTransaction(Container): - payload: BasicTransactionPayload - signature: EcdsaTransactionSignature +class RlpFeeMarketTransaction(Container): + payload: RlpFeeMarketTransactionPayload + signature: EcdsaExecutionSignature -class BlobTransactionPayload(Profile[TransactionPayload]): +class RlpBlobTransactionPayload(Profile[TransactionPayload]): + type_: TransactionType chain_id: ChainId nonce: uint64 max_fees_per_gas: BlobFeesPerGas @@ -197,128 +202,35 @@ class BlobTransactionPayload(Profile[TransactionPayload]): max_priority_fees_per_gas: BlobFeesPerGas blob_versioned_hashes: List[VersionedHash, MAX_BLOB_COMMITMENTS_PER_BLOCK] -class BlobTransaction(Container): - payload: BlobTransactionPayload - signature: EcdsaTransactionSignature - -def select_transaction_profile(value: Transaction) -> Type[Profile]: - if value.payload.type_ is None: - if value.payload.blob_versioned_hashes is not None: - return BlobTransaction - return BasicTransaction - - if value.payload.type_ == TRANSACTION_TYPE_EIP4844: - return Eip4844Transaction - - if value.payload.type_ == TRANSACTION_TYPE_EIP1559: - return Eip1559Transaction - - if value.payload.type_ == TRANSACTION_TYPE_EIP2930: - return Eip2930Transaction - - if value.payload.chain_id is not None: - return LegacyTransaction - - return ReplayableTransaction - -class Root(Bytes32): - pass - -class DomainType(Bytes4): - pass - -class ChainId(uint256): - pass - -DOMAIN_TRANSACTION_SSZ = DomainType('0x04000080') +class RlpBlobTransaction(Container): + payload: RlpBlobTransactionPayload + signature: EcdsaExecutionSignature -class ExecutionSigningData(Container): - object_root: Root - domain_type: DomainType +LEGACY_TX_TYPE = TransactionType(0x00) +ACCESS_LIST_TX_TYPE = TransactionType(0x01) +FEE_MARKET_TX_TYPE = TransactionType(0x02) +BLOB_TX_TYPE = TransactionType(0x03) -def compute_ssz_sig_hash(payload: TransactionPayload) -> Hash32: - return Hash32(ExecutionSigningData( - object_root=payload.hash_tree_root(), - domain=DOMAIN_TRANSACTION_SSZ, - ).hash_tree_root()) +def identify_transaction_profile(tx: Transaction) -> Type[Profile]: + if tx.payload.type_ == BLOB_TX_TYPE: + return RlpBlobTransaction -def compute_ssz_tx_hash(tx: Transaction) -> Hash32: - assert tx.payload.type_ == TRANSACTION_TYPE_SSZ - return Hash32(tx.hash_tree_root()) - -def ecdsa_pack_signature(y_parity: bool, - r: uint256, - s: uint256) -> ByteVector[ECDSA_SIGNATURE_SIZE]: - return r.to_bytes(32, 'big') + s.to_bytes(32, 'big') + bytes([0x01 if y_parity else 0x00]) + if tx.payload.type_ == FEE_MARKET_TX_TYPE: + return RlpFeeMarketTransaction -def ecdsa_unpack_signature(signature: ByteVector[ECDSA_SIGNATURE_SIZE]) -> tuple[bool, uint256, uint256]: - y_parity = signature[64] != 0 - r = uint256.from_bytes(signature[0:32], 'big') - s = uint256.from_bytes(signature[32:64], 'big') - return (y_parity, r, s) + if tx.payload.type_ == ACCESS_LIST_TX_TYPE: + return RlpAccessListTransaction -def ecdsa_validate_signature(signature: ByteVector[ECDSA_SIGNATURE_SIZE]): - SECP256K1N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 - assert len(signature) == 65 - assert signature[64] in (0, 1) - _, r, s = ecdsa_unpack_signature(signature) - assert 0 < r < SECP256K1N - assert 0 < s < SECP256K1N + if tx.payload.type_ == LEGACY_TX_TYPE: + return RlpLegacyTransaction -def ecdsa_recover_from_address(signature: ByteVector[ECDSA_SIGNATURE_SIZE], - sig_hash: Hash32) -> ExecutionAddress: - ecdsa = ECDSA() - recover_sig = ecdsa.ecdsa_recoverable_deserialize(signature[0:64], signature[64]) - public_key = PublicKey(ecdsa.ecdsa_recover(sig_hash, recover_sig, raw=True)) - uncompressed = public_key.serialize(compressed=False) - return ExecutionAddress(keccak(uncompressed[1:])[12:]) + raise Exception(f'Unsupported transaction: {tx}') -from tx_hashes import compute_sig_hash, compute_tx_hash +from tx_hashes import compute_sig_hash -def validate_transaction(tx): +def validate_tx_from_address(tx): ecdsa_validate_signature(tx.signature.ecdsa_signature) assert tx.signature.from_ == ecdsa_recover_from_address( tx.signature.ecdsa_signature, compute_sig_hash(tx), ) - -BYTES_PER_LOGS_BLOOM = uint64(2**8) -MAX_TOPICS_PER_LOG = 4 -MAX_LOG_DATA_SIZE = uint64(2**24) -MAX_LOGS_PER_RECEIPT = uint64(2**21) -MAX_RECEIPT_FIELDS = uint64(2**5) - -class Log(Container): - address: ExecutionAddress - topics: List[Bytes32, MAX_TOPICS_PER_LOG] - data: ByteList[MAX_LOG_DATA_SIZE] - -class Receipt(StableContainer[MAX_RECEIPT_FIELDS]): - root: Optional[Hash32] - gas_used: Optional[uint64] - contract_address: Optional[ExecutionAddress] - logs_bloom: Optional[ByteVector[BYTES_PER_LOGS_BLOOM]] - logs: Optional[List[Log, MAX_LOGS_PER_RECEIPT]] - - # EIP-658 - status: Optional[boolean] - -class HomesteadReceipt(Profile[Receipt]): - root: Hash32 - gas_used: uint64 - contract_address: Optional[ExecutionAddress] - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - logs: List[Log, MAX_LOGS_PER_RECEIPT] - -class BasicReceipt(Profile[Receipt]): - gas_used: uint64 - contract_address: Optional[ExecutionAddress] - logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM] - logs: List[Log, MAX_LOGS_PER_RECEIPT] - status: boolean - -def select_receipt_profile(value: Receipt) -> Type[Profile]: - if value.status is not None: - return BasicReceipt - - return HomesteadReceipt diff --git a/assets/eip-6493/transaction.png b/assets/eip-6404/transaction.png similarity index 100% rename from assets/eip-6493/transaction.png rename to assets/eip-6404/transaction.png diff --git a/assets/eip-6404/tx_hashes.py b/assets/eip-6404/tx_hashes.py new file mode 100644 index 0000000000000..4a567d1e83791 --- /dev/null +++ b/assets/eip-6404/tx_hashes.py @@ -0,0 +1,127 @@ +from rlp_types import * +from ssz_types import * + +def recover_legacy_rlp_transaction( + tx: RlpLegacyTransaction) -> LegacyRlpTransaction: + y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) + if tx.payload.chain_id is not None: # EIP-155 + v = uint64(1 if y_parity else 0) + 35 + tx.payload.chain_id * 2 + else: + v = uint64(1 if y_parity else 0) + 27 + + return LegacyRlpTransaction( + nonce=tx.payload.nonce, + gas_price=tx.payload.max_fees_per_gas.regular, + gas=tx.payload.gas, + to=bytes(tx.payload.to if tx.payload.to is not None else []), + value=tx.payload.value, + data=tx.payload.input_, + v=v, + r=r, + s=s, + ) + +def recover_access_list_rlp_transaction( + tx: RlpAccessListTransaction) -> AccessListRlpTransaction: + y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) + + return AccessListRlpTransaction( + chain_id=tx.payload.chain_id, + nonce=tx.payload.nonce, + gas_price=tx.payload.max_fees_per_gas.regular, + gas=tx.payload.gas, + to=bytes(tx.payload.to if tx.payload.to is not None else []), + value=tx.payload.value, + data=tx.payload.input_, + access_list=[( + access_tuple.address, + access_tuple.storage_keys, + ) for access_tuple in tx.payload.access_list], + y_parity=1 if y_parity else 0, + r=r, + s=s, + ) + +def recover_fee_market_rlp_transaction( + tx: RlpFeeMarketTransaction) -> FeeMarketRlpTransaction: + y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) + + return FeeMarketRlpTransaction( + chain_id=tx.payload.chain_id, + nonce=tx.payload.nonce, + max_priority_fee_per_gas=tx.payload.max_priority_fees_per_gas.regular, + max_fee_per_gas=tx.payload.max_fees_per_gas.regular, + gas=tx.payload.gas, + to=bytes(tx.payload.to if tx.payload.to is not None else []), + value=tx.payload.value, + data=tx.payload.input_, + access_list=[( + access_tuple.address, + access_tuple.storage_keys, + ) for access_tuple in tx.payload.access_list], + y_parity=1 if y_parity else 0, + r=r, + s=s, + ) + +def recover_blob_rlp_transaction(tx: RlpBlobTransaction) -> BlobRlpTransaction: + assert tx.payload.max_priority_fees_per_gas.blob == FeePerGas(0) + y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) + + return BlobRlpTransaction( + chain_id=tx.payload.chain_id, + nonce=tx.payload.nonce, + max_priority_fee_per_gas=tx.payload.max_priority_fees_per_gas.regular, + max_fee_per_gas=tx.payload.max_fees_per_gas.regular, + gas=tx.payload.gas, + to=tx.payload.to, + value=tx.payload.value, + data=tx.payload.input_, + access_list=[( + access_tuple.address, + access_tuple.storage_keys, + ) for access_tuple in tx.payload.access_list], + max_fee_per_blob_gas=tx.payload.max_fees_per_gas.blob, + blob_versioned_hashes=tx.payload.blob_versioned_hashes, + y_parity=1 if y_parity else 0, + r=r, + s=s, + ) + +def compute_sig_hash(tx) -> Hash32: + if isinstance(tx, RlpBlobTransaction): + pre = recover_blob_rlp_transaction(tx) + return compute_blob_sig_hash(pre) + + if isinstance(tx, RlpFeeMarketTransaction): + pre = recover_fee_market_rlp_transaction(tx) + return compute_fee_market_sig_hash(pre) + + if isinstance(tx, RlpAccessListTransaction): + pre = recover_access_list_rlp_transaction(tx) + return compute_access_list_sig_hash(pre) + + if isinstance(tx, RlpLegacyTransaction): + pre = recover_legacy_rlp_transaction(tx) + return compute_legacy_sig_hash(pre) + + raise Exception(f'Unsupported transaction: {tx}') + +def compute_tx_hash(tx) -> Hash32: + if isinstance(tx, RlpBlobTransaction): + pre = recover_blob_rlp_transaction(tx) + return compute_blob_tx_hash(pre) + + if isinstance(tx, RlpFeeMarketTransaction): + pre = recover_fee_market_rlp_transaction(tx) + return compute_fee_market_tx_hash(pre) + + if isinstance(tx, RlpAccessListTransaction): + pre = recover_access_list_rlp_transaction(tx) + return compute_access_list_tx_hash(pre) + + if isinstance(tx, RlpLegacyTransaction): + pre = recover_legacy_rlp_transaction(tx) + return compute_legacy_tx_hash(pre) + + raise Exception(f'Unsupported transaction: {tx}') diff --git a/assets/eip-6493/receipt.png b/assets/eip-6466/receipt.png similarity index 100% rename from assets/eip-6493/receipt.png rename to assets/eip-6466/receipt.png diff --git a/assets/eip-6493/convert.py b/assets/eip-6493/convert.py deleted file mode 100644 index 8d6ed51d1eb4e..0000000000000 --- a/assets/eip-6493/convert.py +++ /dev/null @@ -1,234 +0,0 @@ -from typing import List as PyList -from rlp import decode -from rlp_types import * -from ssz_types import * - -def upgrade_rlp_transaction_to_ssz(pre_bytes: bytes): - type_ = pre_bytes[0] - - if type_ == 0x03: # EIP-4844 - pre = decode(pre_bytes[1:], Eip4844RlpTransaction) - assert pre.signature_y_parity in (0, 1) - ecdsa_signature = ecdsa_pack_signature( - pre.signature_y_parity != 0, - pre.signature_r, - pre.signature_s, - ) - from_ = ecdsa_recover_from_address(ecdsa_signature, compute_eip4844_sig_hash(pre)) - - return Eip4844Transaction( - payload=Eip4844TransactionPayload( - type_=TRANSACTION_TYPE_EIP4844, - chain_id=pre.chain_id, - nonce=pre.nonce, - max_fees_per_gas=BlobFeesPerGas( - regular=pre.max_fee_per_gas, - blob=pre.max_fee_per_blob_gas, - ), - gas=pre.gas_limit, - to=ExecutionAddress(pre.destination), - value=pre.amount, - input_=pre.data, - access_list=[AccessTuple( - address=access_tuple[0], - storage_keys=access_tuple[1] - ) for access_tuple in pre.access_list], - max_priority_fees_per_gas=BlobFeesPerGas( - regular=pre.max_priority_fee_per_gas, - blob=FeePerGas(0), - ), - blob_versioned_hashes=pre.blob_versioned_hashes, - ), - signature=EcdsaTransactionSignature( - from_=from_, - ecdsa_signature=ecdsa_signature, - ), - ) - - if type_ == 0x02: # EIP-1559 - pre = decode(pre_bytes[1:], Eip1559RlpTransaction) - assert pre.signature_y_parity in (0, 1) - ecdsa_signature = ecdsa_pack_signature( - pre.signature_y_parity != 0, - pre.signature_r, - pre.signature_s, - ) - from_ = ecdsa_recover_from_address(ecdsa_signature, compute_eip1559_sig_hash(pre)) - - return Eip1559Transaction( - payload=Eip1559TransactionPayload( - type_=TRANSACTION_TYPE_EIP1559, - chain_id=pre.chain_id, - nonce=pre.nonce, - max_fees_per_gas=BasicFeesPerGas( - regular=pre.max_fee_per_gas, - ), - gas=pre.gas_limit, - to=ExecutionAddress(pre.destination) if len(pre.destination) > 0 else None, - value=pre.amount, - input_=pre.data, - access_list=[AccessTuple( - address=access_tuple[0], - storage_keys=access_tuple[1] - ) for access_tuple in pre.access_list], - max_priority_fees_per_gas=BasicFeesPerGas( - regular=pre.max_priority_fee_per_gas, - ), - ), - signature=EcdsaTransactionSignature( - from_=from_, - ecdsa_signature=ecdsa_signature, - ), - ) - - if type_ == 0x01: # EIP-2930 - pre = decode(pre_bytes[1:], Eip2930RlpTransaction) - assert pre.signatureYParity in (0, 1) - ecdsa_signature = ecdsa_pack_signature( - pre.signatureYParity != 0, - pre.signatureR, - pre.signatureS - ) - from_ = ecdsa_recover_from_address(ecdsa_signature, compute_eip2930_sig_hash(pre)) - - return Eip2930Transaction( - payload=Eip2930TransactionPayload( - type_=TRANSACTION_TYPE_EIP2930, - chain_id=pre.chainId, - nonce=pre.nonce, - max_fees_per_gas=BasicFeesPerGas( - regular=pre.gasPrice, - ), - gas=pre.gasLimit, - to=ExecutionAddress(pre.to) if len(pre.to) > 0 else None, - value=pre.value, - input_=pre.data, - access_list=[AccessTuple( - address=access_tuple[0], - storage_keys=access_tuple[1] - ) for access_tuple in pre.accessList], - ), - signature=EcdsaTransactionSignature( - from_=from_, - ecdsa_signature=ecdsa_signature, - ), - ) - - if 0xc0 <= type_ <= 0xfe: # Legacy - pre = decode(pre_bytes, LegacyRlpTransaction) - ecdsa_signature = ecdsa_pack_signature( - (pre.v & 0x1) == 0, - pre.r, - pre.s, - ) - from_ = ecdsa_recover_from_address(ecdsa_signature, compute_legacy_sig_hash(pre)) - - if (pre.v not in (27, 28)): # EIP-155 - chain_id = ((pre.v - 35) >> 1) - return LegacyTransaction( - payload=LegacyTransactionPayload( - type_=TRANSACTION_TYPE_LEGACY, - chain_id=chain_id, - nonce=pre.nonce, - max_fees_per_gas=BasicFeesPerGas( - regular=pre.gasprice, - ), - gas=pre.startgas, - to=ExecutionAddress(pre.to) if len(pre.to) > 0 else None, - value=pre.value, - input_=pre.data, - ), - signature=EcdsaTransactionSignature( - from_=from_, - ecdsa_signature=ecdsa_signature, - ), - ) - - return ReplayableTransaction( - payload=ReplayableTransactionPayload( - type_=TRANSACTION_TYPE_LEGACY, - nonce=pre.nonce, - max_fees_per_gas=BasicFeesPerGas( - regular=pre.gasprice, - ), - gas=pre.startgas, - to=ExecutionAddress(pre.to) if len(pre.to) > 0 else None, - value=pre.value, - input_=pre.data, - ), - signature=EcdsaTransactionSignature( - from_=from_, - ecdsa_signature=ecdsa_signature, - ), - ) - - assert False - -class ContractAddressData(Serializable): - fields = ( - ('from_', Binary(20, 20)), - ('nonce', big_endian_int), - ) - -def compute_contract_address(from_: ExecutionAddress, - nonce: uint64) -> ExecutionAddress: - return ExecutionAddress(keccak(encode(ContractAddressData( - from_=from_, - nonce=nonce, - )))[12:32]) - -def upgrade_rlp_receipt_to_ssz(pre_bytes: bytes, - prev_cumulative_gas_used: uint64, - transaction): - type_ = pre_bytes[0] - - if type_ in (0x03, 0x02, 0x01): # EIP-4844, EIP-1559, EIP-2930 - pre = decode(pre_bytes[1:], RlpReceipt) - elif 0xc0 <= type_ <= 0xfe: # Legacy - pre = decode(pre_bytes, RlpReceipt) - else: - assert False - - if len(pre.post_state_or_status) != 32: - status = len(pre.post_state_or_status) > 0 and pre.post_state_or_status[0] != 0 - - return BasicReceipt( - gas_used=pre.cumulative_gas_used - prev_cumulative_gas_used, - contract_address=compute_contract_address( - transaction.signature.from_, - transaction.payload.nonce, - ) if transaction.payload.to is None else None, - logs_bloom=pre.logs_bloom, - logs=[Log( - address=log[0], - topics=log[1], - data=log[2], - ) for log in pre.logs], - status=status, - ) - - root = pre.post_state_or_status - return HomesteadReceipt( - root=root, - gas_used=pre.cumulative_gas_used - prev_cumulative_gas_used, - contract_address=compute_contract_address( - transaction.signature.from_, - transaction.payload.nonce, - ) if transaction.payload.to is None else None, - logs_bloom=pre.logs_bloom, - logs=[Log( - address=log[0], - topics=log[1], - data=log[2], - ) for log in pre.logs], - ) - -def upgrade_rlp_receipts_to_ssz(pre_bytes_list: PyList[bytes], - transactions: PyList) -> PyList: - receipts = [] - cumulative_gas_used = 0 - for i, pre_bytes in enumerate(pre_bytes_list): - receipt = upgrade_rlp_receipt_to_ssz(pre_bytes, cumulative_gas_used, transactions[i]) - cumulative_gas_used += receipt.gas_used - receipts.append(receipt) - return receipts diff --git a/assets/eip-6493/tx_hashes.py b/assets/eip-6493/tx_hashes.py deleted file mode 100644 index c71a7450f7fe3..0000000000000 --- a/assets/eip-6493/tx_hashes.py +++ /dev/null @@ -1,157 +0,0 @@ -from rlp_types import * -from ssz_types import * - -def recover_replayable_rlp_transaction( - tx: ReplayableTransaction) -> LegacyRlpTransaction: - y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) - v = uint64(1 if y_parity else 0) + 27 - - return LegacyRlpTransaction( - nonce=tx.payload.nonce, - gasprice=tx.payload.max_fees_per_gas.regular, - startgas=tx.payload.gas, - to=bytes(tx.payload.to if tx.payload.to is not None else []), - value=tx.payload.value, - data=tx.payload.input_, - v=v, - r=r, - s=s, - ) - -def recover_legacy_rlp_transaction( - tx: LegacyTransaction) -> LegacyRlpTransaction: - y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) - v = uint64(1 if y_parity else 0) + 35 + tx.payload.chain_id * 2 - - return LegacyRlpTransaction( - nonce=tx.payload.nonce, - gasprice=tx.payload.max_fees_per_gas.regular, - startgas=tx.payload.gas, - to=bytes(tx.payload.to if tx.payload.to is not None else []), - value=tx.payload.value, - data=tx.payload.input_, - v=v, - r=r, - s=s, - ) - -def recover_eip2930_rlp_transaction( - tx: Eip2930Transaction) -> Eip2930RlpTransaction: - y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) - - return Eip2930RlpTransaction( - chainId=tx.payload.chain_id, - nonce=tx.payload.nonce, - gasPrice=tx.payload.max_fees_per_gas.regular, - gasLimit=tx.payload.gas, - to=bytes(tx.payload.to if tx.payload.to is not None else []), - value=tx.payload.value, - data=tx.payload.input_, - accessList=[( - access_tuple.address, - access_tuple.storage_keys, - ) for access_tuple in tx.payload.access_list], - signatureYParity=1 if y_parity else 0, - signatureR=r, - signatureS=s, - ) - -def recover_eip1559_rlp_transaction( - tx: Eip1559Transaction) -> Eip1559RlpTransaction: - y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) - - return Eip1559RlpTransaction( - chain_id=tx.payload.chain_id, - nonce=tx.payload.nonce, - max_priority_fee_per_gas=tx.payload.max_priority_fees_per_gas.regular, - max_fee_per_gas=tx.payload.max_fees_per_gas.regular, - gas_limit=tx.payload.gas, - destination=bytes(tx.payload.to if tx.payload.to is not None else []), - amount=tx.payload.value, - data=tx.payload.input_, - access_list=[( - access_tuple.address, - access_tuple.storage_keys, - ) for access_tuple in tx.payload.access_list], - signature_y_parity=1 if y_parity else 0, - signature_r=r, - signature_s=s, - ) - -def recover_eip4844_rlp_transaction(tx: Eip4844Transaction) -> Eip4844RlpTransaction: - assert tx.payload.max_priority_fees_per_gas.blob == FeePerGas(0) - y_parity, r, s = ecdsa_unpack_signature(tx.signature.ecdsa_signature) - - return Eip4844RlpTransaction( - chain_id=tx.payload.chain_id, - nonce=tx.payload.nonce, - max_priority_fee_per_gas=tx.payload.max_priority_fees_per_gas.regular, - max_fee_per_gas=tx.payload.max_fees_per_gas.regular, - gas_limit=tx.payload.gas, - to=tx.payload.to, - value=tx.payload.value, - data=tx.payload.input_, - access_list=[( - access_tuple.address, - access_tuple.storage_keys, - ) for access_tuple in tx.payload.access_list], - max_fee_per_blob_gas=tx.payload.max_fees_per_gas.blob, - blob_versioned_hashes=tx.payload.blob_versioned_hashes, - signature_y_parity=1 if y_parity else 0, - signature_r=r, - signature_s=s, - ) - -def compute_sig_hash(tx) -> Hash32: - if ( - isinstance(tx, BasicTransaction) or - isinstance(tx, BlobTransaction) - ): - return compute_ssz_sig_hash(tx.payload) - - if isinstance(tx, Eip4844Transaction): - pre = recover_eip4844_rlp_transaction(tx) - return compute_eip4844_sig_hash(pre) - - if isinstance(tx, Eip1559Transaction): - pre = recover_eip1559_rlp_transaction(tx) - return compute_eip1559_sig_hash(pre) - - if isinstance(tx, Eip2930Transaction): - pre = recover_eip2930_rlp_transaction(tx) - return compute_eip2930_sig_hash(pre) - - if isinstance(tx, LegacyTransaction): - pre = recover_legacy_rlp_transaction(tx) - return compute_legacy_sig_hash(pre) - - assert isinstance(tx, ReplayableTransaction) - pre = recover_replayable_rlp_transaction(tx) - return compute_legacy_sig_hash(pre) - -def compute_tx_hash(tx) -> Hash32: - if ( - isinstance(tx, BasicTransaction) or - isinstance(tx, BlobTransaction) - ): - return compute_ssz_tx_hash(tx.payload) - - if isinstance(tx, Eip4844Transaction): - pre = recover_eip4844_rlp_transaction(tx) - return compute_eip4844_tx_hash(pre) - - if isinstance(tx, Eip1559Transaction): - pre = recover_eip1559_rlp_transaction(tx) - return compute_eip1559_tx_hash(pre) - - if isinstance(tx, Eip2930Transaction): - pre = recover_eip2930_rlp_transaction(tx) - return compute_eip2930_tx_hash(pre) - - if isinstance(tx, LegacyTransaction): - pre = recover_legacy_rlp_transaction(tx) - return compute_legacy_tx_hash(pre) - - assert isinstance(tx, ReplayableTransaction) - pre = recover_replayable_rlp_transaction(tx) - return compute_legacy_tx_hash(pre)