From efd11c83c53eda59f3ee0db70c4e0cec90512d06 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Wed, 25 Sep 2024 12:45:50 -0600 Subject: [PATCH 1/3] Add ephemeral block headers to the history network spec --- history/history-network.md | 49 ++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/history/history-network.md b/history/history-network.md index 375b4d2..a5d52bd 100644 --- a/history/history-network.md +++ b/history/history-network.md @@ -64,10 +64,13 @@ The history network supports the following protocol messages: In the history network the `custom_payload` field of the `Ping` and `Pong` messages is the serialization of an SSZ Container specified as `custom_data`: ```python -custom_data = Container(data_radius: uint256) +custom_data = Container(data_radius: uint256, ephemeral_header_count: uint16) custom_payload = SSZ.serialize(custom_data) ``` +* The `data_radius` value defines the *distance* from the node's node-id for which other clients may assume the node would be interested in content. +* The `ephemeral_header_count` value defines the number of *recent* headers that this node stores. The maximum effective value for this is 8192. + ### Routing Table The history network uses the standard routing table structure from the Portal Wire Protocol. @@ -79,7 +82,7 @@ The history network uses the standard routing table structure from the Portal Wi The history network includes one additional piece of node state that should be tracked. Nodes must track the `data_radius` from the Ping and Pong messages for other nodes in the network. This value is a 256 bit integer and represents the data that a node is "interested" in. We define the following function to determine whether node in the network should be interested in a piece of content. ```python -interested(node, content) = distance(node.id, content.id) <= node.radius +interested(node, content) = distance(node.id, content.id) <= node.data_radius ``` A node is expected to maintain `radius` information for each node in its local node table. A node's `radius` value may fluctuate as the contents of its local key-value store change. @@ -135,6 +138,10 @@ WITHDRAWAL_LENGTH = 64 SHANGHAI_TIMESTAMP = 1681338455 # Number sourced from EIP-4895 + +MAX_EPHEMERAL_HEADER_PAYLOAD = 256 +# The maximum number of ephemeral headers that can be requested or transferred +# in a single request. ``` #### Encoding Content Values for Validation @@ -157,7 +164,7 @@ each receipt/transaction and re-rlp-encode it, but only if it is a legacy transa HistoricalHashesAccumulatorProof = Vector[Bytes32, 15] -BlockHeaderProof = Union[None, HistoricalHashesAccumulatorProof] +BlockHeaderProof = Union[HistoricalHashesAccumulatorProof] BlockHeaderWithProof = Container( header: ByteList[MAX_HEADER_LENGTH], # RLP encoded header in SSZ ByteList @@ -166,7 +173,7 @@ BlockHeaderWithProof = Container( ``` > **_Note:_** The `BlockHeaderProof` allows to provide headers without a proof (`None`). -For pre-merge headers, clients SHOULD NOT accept headers without a proof +For pre-merge headers, clients **SHOULD NOT** accept headers without a proof as there is the `HistoricalHashesAccumulatorProof` solution available. For post-merge headers, there is currently no proof solution and clients MAY accept headers without a proof. @@ -200,6 +207,40 @@ content = SSZ.serialize(block_header_with_proof) content_key = selector + SSZ.serialize(block_number_key) ``` +##### Ephemeral Block Headers + +This content type represents block headers *near* the HEAD of the chain. They are provable by tracing through the chain of `header.parent_hash` values. All nodes in the network are assumed to store some amount of this content. The `Ping.custom_data` and `Pong.custom_data` fields can be used to learn the number of recent headers that a client makes available. + +> Note: The history network does not provide a mechanism for knowing the HEAD of the chain. Clients to this network **MUST** have an external oracle for this information. The Portal Beacon Network is able to provide this information. + +> Note: The content-id for this data type is not meaningful. + +> Note: This message is not valid for Gossip. Clients **SHOULD** not send or accept gossip messages for this content type. + +> Note: Clients **SHOULD** implement a mechanism to purge headers older than 8192 blocks from their content databases. + +```python +# Content and content key + +ephemeral_headers_key = Container(block_hash: Bytes32, ancestor_count: uint8) +selector = 0x04 + +BlockHeader = ByteList[MAX_HEADER_LENGTH] +ephemeral_header_payload = List(BlockHeader, limit=MAX_EPHEMERAL_HEADER_PAYLOAD) + +content = SSZ.serialize(ephemeral_header_payload) +content_key = selector + SSZ.serialize(ephemeral_headers_key) +``` + +The `ephemeral_header_payload` is an SSZ list of RLP encoded block header +objects. The this object is subject to the following validity conditions. + +* The list **MAY** be empty which signals that the responding node was unable to fulfill the request. +* The first element in the list **MUST** be the RLP encoded block header indicated by the `ephemeral_headers_key.block_hash` field from the content key. +* Each element after the first element in the list **MUST** be the RLP encoded block header indicated by the `header.parent_hash` of the previous item from the list. +* The list **SHOULD** contain no more than `ephemeral_headers_key.ancestor_count` items. + + #### Block Body After the addition of `withdrawals` to the block body in the [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895), From 18e7f3ef0f47d46652884c104d202d782ab8204e Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Mon, 30 Sep 2024 09:03:32 -0600 Subject: [PATCH 2/3] explicit language about the ephemeral_headers_key validity --- history/history-network.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/history/history-network.md b/history/history-network.md index a5d52bd..412a5f6 100644 --- a/history/history-network.md +++ b/history/history-network.md @@ -232,6 +232,11 @@ content = SSZ.serialize(ephemeral_header_payload) content_key = selector + SSZ.serialize(ephemeral_headers_key) ``` +The `ephemeral_headers_key` encodes a request for headers anchored to the block +hash indicated by `ephemeral_headers_key.block_hash`. The +`ephemeral_headers_key.ancestor_count` **MUST** be in the inclusive range +0-255. + The `ephemeral_header_payload` is an SSZ list of RLP encoded block header objects. The this object is subject to the following validity conditions. From c2fdc620ec33c52910703f41504b0ab883648a35 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Wed, 20 Nov 2024 11:54:04 -0700 Subject: [PATCH 3/3] Update history/history-network.md --- history/history-network.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/history/history-network.md b/history/history-network.md index 412a5f6..16c67ef 100644 --- a/history/history-network.md +++ b/history/history-network.md @@ -215,7 +215,7 @@ This content type represents block headers *near* the HEAD of the chain. They a > Note: The content-id for this data type is not meaningful. -> Note: This message is not valid for Gossip. Clients **SHOULD** not send or accept gossip messages for this content type. +> Note: This message is not valid for Gossip (OFFER/ACCEPT). Clients **SHOULD** not send or accept gossip messages for this content type. > Note: Clients **SHOULD** implement a mechanism to purge headers older than 8192 blocks from their content databases.