Skip to main content

reth_network_p2p/snap/
client.rs

1use crate::{download::DownloadClient, error::PeerRequestResult, priority::Priority};
2use futures::Future;
3use reth_eth_wire_types::snap::{
4    AccountRangeMessage, BlockAccessListsMessage, ByteCodesMessage, GetAccountRangeMessage,
5    GetBlockAccessListsMessage, GetByteCodesMessage, GetStorageRangesMessage, SnapProtocolMessage,
6    StorageRangesMessage,
7};
8
9/// Response types for snap sync requests
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum SnapResponse {
12    /// Response containing account range data
13    AccountRange(AccountRangeMessage),
14    /// Response containing storage ranges data
15    StorageRanges(StorageRangesMessage),
16    /// Response containing bytecode data
17    ByteCodes(ByteCodesMessage),
18    /// Response containing block access lists.
19    ///
20    /// Only valid for `snap/2` (EIP-8189).
21    BlockAccessLists(BlockAccessListsMessage),
22}
23
24impl TryFrom<SnapProtocolMessage> for SnapResponse {
25    /// The original message, returned unchanged when it is a request rather than a response.
26    type Error = SnapProtocolMessage;
27
28    fn try_from(msg: SnapProtocolMessage) -> Result<Self, Self::Error> {
29        match msg {
30            SnapProtocolMessage::AccountRange(m) => Ok(Self::AccountRange(m)),
31            SnapProtocolMessage::StorageRanges(m) => Ok(Self::StorageRanges(m)),
32            SnapProtocolMessage::ByteCodes(m) => Ok(Self::ByteCodes(m)),
33            SnapProtocolMessage::BlockAccessLists(m) => Ok(Self::BlockAccessLists(m)),
34            request => Err(request),
35        }
36    }
37}
38
39impl From<SnapResponse> for SnapProtocolMessage {
40    fn from(response: SnapResponse) -> Self {
41        match response {
42            SnapResponse::AccountRange(m) => Self::AccountRange(m),
43            SnapResponse::StorageRanges(m) => Self::StorageRanges(m),
44            SnapResponse::ByteCodes(m) => Self::ByteCodes(m),
45            SnapResponse::BlockAccessLists(m) => Self::BlockAccessLists(m),
46        }
47    }
48}
49
50/// The snap sync downloader client
51#[auto_impl::auto_impl(&, Arc, Box)]
52pub trait SnapClient: DownloadClient {
53    /// The output future type for snap requests
54    type Output: Future<Output = PeerRequestResult<SnapResponse>> + Send + Sync + Unpin;
55
56    /// Sends the account range request to the p2p network and returns the account range
57    /// response received from a peer.
58    fn get_account_range(&self, request: GetAccountRangeMessage) -> Self::Output {
59        self.get_account_range_with_priority(request, Priority::Normal)
60    }
61
62    /// Sends the account range request to the p2p network with priority set and returns
63    /// the account range response received from a peer.
64    fn get_account_range_with_priority(
65        &self,
66        request: GetAccountRangeMessage,
67        priority: Priority,
68    ) -> Self::Output;
69
70    /// Sends the storage ranges request to the p2p network and returns the storage ranges
71    /// response received from a peer.
72    fn get_storage_ranges(&self, request: GetStorageRangesMessage) -> Self::Output;
73
74    /// Sends the storage ranges request to the p2p network with priority set and returns
75    /// the storage ranges response received from a peer.
76    fn get_storage_ranges_with_priority(
77        &self,
78        request: GetStorageRangesMessage,
79        priority: Priority,
80    ) -> Self::Output;
81
82    /// Sends the byte codes request to the p2p network and returns the byte codes
83    /// response received from a peer.
84    fn get_byte_codes(&self, request: GetByteCodesMessage) -> Self::Output;
85
86    /// Sends the byte codes request to the p2p network with priority set and returns
87    /// the byte codes response received from a peer.
88    fn get_byte_codes_with_priority(
89        &self,
90        request: GetByteCodesMessage,
91        priority: Priority,
92    ) -> Self::Output;
93
94    /// Sends the block access lists request to the p2p network and returns the block
95    /// access lists response received from a peer.
96    ///
97    /// Only valid for `snap/2` (EIP-8189).
98    fn get_block_access_lists(&self, request: GetBlockAccessListsMessage) -> Self::Output {
99        self.get_block_access_lists_with_priority(request, Priority::Normal)
100    }
101
102    /// Sends the block access lists request to the p2p network with priority set and returns
103    /// the block access lists response received from a peer.
104    ///
105    /// Only valid for `snap/2` (EIP-8189).
106    fn get_block_access_lists_with_priority(
107        &self,
108        request: GetBlockAccessListsMessage,
109        priority: Priority,
110    ) -> Self::Output;
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116    use reth_eth_wire_types::BlockAccessLists;
117    use test_case::test_case;
118
119    #[test_case(
120        SnapProtocolMessage::GetAccountRange(GetAccountRangeMessage {
121            request_id: 1, root_hash: Default::default(), starting_hash: Default::default(),
122            limit_hash: Default::default(), response_bytes: 0,
123        }), false ; "account range request is not a response"
124    )]
125    #[test_case(
126        SnapProtocolMessage::GetBlockAccessLists(GetBlockAccessListsMessage {
127            request_id: 1, block_hashes: vec![], response_bytes: 0,
128        }), false ; "block access lists request is not a response"
129    )]
130    #[test_case(
131        SnapProtocolMessage::AccountRange(AccountRangeMessage {
132            request_id: 1, accounts: vec![], proof: vec![],
133        }), true ; "account range response converts"
134    )]
135    #[test_case(
136        SnapProtocolMessage::ByteCodes(ByteCodesMessage { request_id: 1, codes: vec![] }),
137        true ; "byte codes response converts"
138    )]
139    #[test_case(
140        SnapProtocolMessage::BlockAccessLists(BlockAccessListsMessage {
141            request_id: 1, block_access_lists: BlockAccessLists(vec![]),
142        }), true ; "block access lists response converts"
143    )]
144    fn try_from_snap_message(msg: SnapProtocolMessage, is_response: bool) {
145        let original = msg.clone();
146        match SnapResponse::try_from(msg) {
147            Ok(_) => assert!(is_response),
148            // requests are returned unchanged
149            Err(returned) => {
150                assert!(!is_response);
151                assert_eq!(returned, original);
152            }
153        }
154    }
155}