From 24d8a8da11c31a2cbaf27ab5d72eec5643e5b593 Mon Sep 17 00:00:00 2001 From: lean-apple <78718413+lean-apple@users.noreply.github.com> Date: Thu, 30 Jan 2025 22:37:17 +0100 Subject: [PATCH 1/2] feat: draft to add snap protocol msg --- crates/net/eth-wire-types/src/lib.rs | 3 + crates/net/eth-wire-types/src/snap.rs | 177 ++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 crates/net/eth-wire-types/src/snap.rs diff --git a/crates/net/eth-wire-types/src/lib.rs b/crates/net/eth-wire-types/src/lib.rs index 011173e71a2c..686c21abd601 100644 --- a/crates/net/eth-wire-types/src/lib.rs +++ b/crates/net/eth-wire-types/src/lib.rs @@ -46,3 +46,6 @@ pub use capability::*; pub mod primitives; pub use primitives::*; + +mod snap; +pub use snap::*; diff --git a/crates/net/eth-wire-types/src/snap.rs b/crates/net/eth-wire-types/src/snap.rs new file mode 100644 index 000000000000..6590e86c632f --- /dev/null +++ b/crates/net/eth-wire-types/src/snap.rs @@ -0,0 +1,177 @@ +use alloy_primitives::{Bytes, B256}; + +/// Message IDs for the snap sync protocol +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SnapMessageId { + /// Requests of an unknown number of accounts from a given account trie. + GetAccountRange = 0x00, + /// Response with the number of consecutive accounts and the Merkle proofs for the entire + /// range. + AccountRange = 0x01, + /// Requests for the storage slots of multiple accounts' storage tries. + GetStorageRanges = 0x02, + /// Response for the number of consecutive storage slots for the requested account. + StorageRanges = 0x03, + /// Request of the number of contract byte-codes by hash. + GetByteCodes = 0x04, + /// Response for the number of requested contract codes. + ByteCodes = 0x05, + /// Request of the number of state (either account or storage) Merkle trie nodes by path. + GetTrieNodes = 0x06, + /// Response for the number of requested state trie nodes. + TrieNodes = 0x07, +} + +/// Request for a range of accounts from the state trie +/// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#getaccountrange-0x00 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct GetAccountRangeMessage { + /// Request ID to match up responses with + pub request_id: u64, + /// Root hash of the account trie to serve + pub root_hash: B256, + /// Account hash of the first to retrieve + pub starting_hash: B256, + /// Account hash after which to stop serving data + pub limit_hash: B256, + /// Soft limit at which to stop returning data (in bytes) + pub response_bytes: u64, +} + +/// Account data in the response +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AccountData { + /// Hash of the account address (trie path) + pub hash: B256, + /// Account body in slim format + pub body: Bytes, +} + +/// Response containing a range of accounts and their proofs +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AccountRangeMessage { + /// ID of the request this is a response for + pub request_id: u64, + /// List of consecutive accounts from the trie + pub accounts: Vec, + /// List of trie nodes proving the account range + pub proof: Vec, +} + +/// Request for storage slots from multiple accounts +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct GetStorageRangesMessage { + /// Request ID to match up responses with + pub request_id: u64, + /// Root hash of the account trie to serve + pub root_hash: B256, + /// Account hashes of the storage tries to serve + pub account_hashes: Vec, + /// Storage slot hash of the first to retrieve + pub starting_hash: B256, + /// Storage slot hash after which to stop serving + pub limit_hash: B256, + /// Soft limit at which to stop returning data (in bytes) + pub response_bytes: u64, +} + +/// Storage slot data in the response +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StorageData { + /// Hash of the storage slot key (trie path) + pub hash: B256, + /// Data content of the slot + pub data: Bytes, +} + +/// Response containing a number of consecutive storage slots for the requested account +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StorageRangesMessage { + /// ID of the request this is a response for + pub request_id: u64, + /// List of list of consecutive slots from the trie (one list per account) + pub slots: Vec>, + /// List of trie nodes proving the slot range (if partial) + pub proof: Vec, +} + +/// Request for contract bytecodes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct GetByteCodesMessage { + /// Request ID to match up responses with + pub request_id: u64, + /// Code hashes to retrieve the code for + pub hashes: Vec, + /// Soft limit at which to stop returning data (in bytes) + pub response_bytes: u64, +} + +/// Response containing requested contract bytecodes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ByteCodesMessage { + /// ID of the request this is a response for + pub request_id: u64, + /// The requested bytecodes in order + pub codes: Vec, +} + +/// Path in the trie for an account and its storage +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TriePath { + /// Path in the account trie + pub account_path: Bytes, + /// Paths in the storage trie + pub slot_paths: Vec, +} + +/// Request a number of state (either account or storage) Merkle trie nodes by path +/// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#gettrienodes-0x06 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct GetTrieNodesMessage { + /// Request ID to match up responses with + pub request_id: u64, + /// Root hash of the account trie to serve + pub root_hash: B256, + /// Trie paths to retrieve the nodes for, grouped by account + pub paths: Vec, + /// Soft limit at which to stop returning data (in bytes) + pub response_bytes: u64, +} + +/// Response containing requested trie nodes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TrieNodesMessage { + /// ID of the request this is a response for + pub request_id: u64, + /// The requested trie nodes in order + pub nodes: Vec, +} + +/// Represents all possible snap sync protocol messages +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SnapProtocolMessage { + GetAccountRange(GetAccountRangeMessage), + AccountRange(AccountRangeMessage), + GetStorageRanges(GetStorageRangesMessage), + StorageRanges(StorageRangesMessage), + GetByteCodes(GetByteCodesMessage), + ByteCodes(ByteCodesMessage), + GetTrieNodes(GetTrieNodesMessage), + TrieNodes(TrieNodesMessage), +} + +impl SnapProtocolMessage { + /// Get the message ID for this message type + pub const fn message_id(&self) -> SnapMessageId { + match self { + Self::GetAccountRange(_) => SnapMessageId::GetAccountRange, + Self::AccountRange(_) => SnapMessageId::AccountRange, + Self::GetStorageRanges(_) => SnapMessageId::GetStorageRanges, + Self::StorageRanges(_) => SnapMessageId::StorageRanges, + Self::GetByteCodes(_) => SnapMessageId::GetByteCodes, + Self::ByteCodes(_) => SnapMessageId::ByteCodes, + Self::GetTrieNodes(_) => SnapMessageId::GetTrieNodes, + Self::TrieNodes(_) => SnapMessageId::TrieNodes, + } + } +} From 93bbc4e84ec1e214cf8287c4f057aeadfc3f430b Mon Sep 17 00:00:00 2001 From: lean-apple <78718413+lean-apple@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:46:34 +0100 Subject: [PATCH 2/2] docs: finish types documentation + use no_std compatible imports --- crates/net/eth-wire-types/src/snap.rs | 54 ++++++++++++++++++++------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/crates/net/eth-wire-types/src/snap.rs b/crates/net/eth-wire-types/src/snap.rs index 6590e86c632f..38794a43c1a0 100644 --- a/crates/net/eth-wire-types/src/snap.rs +++ b/crates/net/eth-wire-types/src/snap.rs @@ -1,3 +1,11 @@ +//! Implements Ethereum SNAP message types. +//! Snap protocol runs on top of `RLPx` +//! facilitating the exchange of Ethereum state snapshots between peers +//! Reference: [Ethereum Snapshot Protocol](https://github.com/ethereum/devp2p/blob/master/caps/snap.md#protocol-messages) +//! +//! Current version: snap/1 + +use alloc::vec::Vec; use alloy_primitives::{Bytes, B256}; /// Message IDs for the snap sync protocol @@ -22,8 +30,8 @@ pub enum SnapMessageId { TrieNodes = 0x07, } -/// Request for a range of accounts from the state trie -/// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#getaccountrange-0x00 +/// Request for a range of accounts from the state trie. +// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#getaccountrange-0x00 #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetAccountRangeMessage { /// Request ID to match up responses with @@ -34,11 +42,11 @@ pub struct GetAccountRangeMessage { pub starting_hash: B256, /// Account hash after which to stop serving data pub limit_hash: B256, - /// Soft limit at which to stop returning data (in bytes) + /// Soft limit at which to stop returning data pub response_bytes: u64, } -/// Account data in the response +/// Account data in the response. #[derive(Debug, Clone, PartialEq, Eq)] pub struct AccountData { /// Hash of the account address (trie path) @@ -47,7 +55,8 @@ pub struct AccountData { pub body: Bytes, } -/// Response containing a range of accounts and their proofs +/// Response containing a number of consecutive accounts and the Merkle proofs for the entire range. +// http://github.com/ethereum/devp2p/blob/master/caps/snap.md#accountrange-0x01 #[derive(Debug, Clone, PartialEq, Eq)] pub struct AccountRangeMessage { /// ID of the request this is a response for @@ -58,7 +67,8 @@ pub struct AccountRangeMessage { pub proof: Vec, } -/// Request for storage slots from multiple accounts +/// Request for the storage slots of multiple accounts' storage tries. +// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#getstorageranges-0x02 #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetStorageRangesMessage { /// Request ID to match up responses with @@ -71,11 +81,11 @@ pub struct GetStorageRangesMessage { pub starting_hash: B256, /// Storage slot hash after which to stop serving pub limit_hash: B256, - /// Soft limit at which to stop returning data (in bytes) + /// Soft limit at which to stop returning data pub response_bytes: u64, } -/// Storage slot data in the response +/// Storage slot data in the response. #[derive(Debug, Clone, PartialEq, Eq)] pub struct StorageData { /// Hash of the storage slot key (trie path) @@ -85,6 +95,9 @@ pub struct StorageData { } /// Response containing a number of consecutive storage slots for the requested account +/// and optionally the merkle proofs for the last range (boundary proofs) if it only partially +/// covers the storage trie. +// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#storageranges-0x03 #[derive(Debug, Clone, PartialEq, Eq)] pub struct StorageRangesMessage { /// ID of the request this is a response for @@ -95,7 +108,8 @@ pub struct StorageRangesMessage { pub proof: Vec, } -/// Request for contract bytecodes +/// Request to get a number of requested contract codes. +// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#getbytecodes-0x04 #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetByteCodesMessage { /// Request ID to match up responses with @@ -106,7 +120,8 @@ pub struct GetByteCodesMessage { pub response_bytes: u64, } -/// Response containing requested contract bytecodes +/// Response containing a number of requested contract codes. +// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#bytecodes-0x05 #[derive(Debug, Clone, PartialEq, Eq)] pub struct ByteCodesMessage { /// ID of the request this is a response for @@ -125,7 +140,7 @@ pub struct TriePath { } /// Request a number of state (either account or storage) Merkle trie nodes by path -/// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#gettrienodes-0x06 +// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#gettrienodes-0x06 #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetTrieNodesMessage { /// Request ID to match up responses with @@ -138,7 +153,8 @@ pub struct GetTrieNodesMessage { pub response_bytes: u64, } -/// Response containing requested trie nodes +/// Response containing a number of requested state trie nodes +// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#trienodes-0x07 #[derive(Debug, Clone, PartialEq, Eq)] pub struct TrieNodesMessage { /// ID of the request this is a response for @@ -147,21 +163,31 @@ pub struct TrieNodesMessage { pub nodes: Vec, } -/// Represents all possible snap sync protocol messages +/// Represents all types of messages in the snap sync protocol. #[derive(Debug, Clone, PartialEq, Eq)] pub enum SnapProtocolMessage { + /// Request for an account range - see [`GetAccountRangeMessage`] GetAccountRange(GetAccountRangeMessage), + /// Response with accounts and proofs - see [`AccountRangeMessage`] AccountRange(AccountRangeMessage), + /// Request for storage slots - see [`GetStorageRangesMessage`] GetStorageRanges(GetStorageRangesMessage), + /// Response with storage slots - see [`StorageRangesMessage`] StorageRanges(StorageRangesMessage), + /// Request for contract bytecodes - see [`GetByteCodesMessage`] GetByteCodes(GetByteCodesMessage), + /// Response with contract codes - see [`ByteCodesMessage`] ByteCodes(ByteCodesMessage), + /// Request for trie nodes - see [`GetTrieNodesMessage`] GetTrieNodes(GetTrieNodesMessage), + /// Response with trie nodes - see [`TrieNodesMessage`] TrieNodes(TrieNodesMessage), } impl SnapProtocolMessage { - /// Get the message ID for this message type + /// Returns the protocol message ID for this message type. + /// + /// The message ID is used in the `RLPx` protocol to identify different types of messages. pub const fn message_id(&self) -> SnapMessageId { match self { Self::GetAccountRange(_) => SnapMessageId::GetAccountRange,