/__w/smoldot/smoldot/repo/lib/src/network/codec/kademlia.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Smoldot |
2 | | // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. |
3 | | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 |
4 | | |
5 | | // This program is free software: you can redistribute it and/or modify |
6 | | // it under the terms of the GNU General Public License as published by |
7 | | // the Free Software Foundation, either version 3 of the License, or |
8 | | // (at your option) any later version. |
9 | | |
10 | | // This program is distributed in the hope that it will be useful, |
11 | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | // GNU General Public License for more details. |
14 | | |
15 | | // You should have received a copy of the GNU General Public License |
16 | | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | |
18 | | use crate::{libp2p::peer_id, util::protobuf}; |
19 | | |
20 | | use alloc::vec::Vec; |
21 | | |
22 | | // See https://github.com/libp2p/specs/tree/master/kad-dht#rpc-messages for the protobuf format. |
23 | | |
24 | | /// Builds a wire message to send on the Kademlia request-response protocol to ask the target to |
25 | | /// return the nodes closest to the parameter. |
26 | | // TODO: parameter type? |
27 | 0 | pub fn build_find_node_request(peer_id: &[u8]) -> Vec<u8> { |
28 | 0 | // The capacity is arbitrary but large enough to avoid Vec reallocations. |
29 | 0 | let mut out = Vec::with_capacity(64 + peer_id.len()); |
30 | 0 | for slice in protobuf::enum_tag_encode(1, 4) { |
31 | 0 | out.extend_from_slice(slice.as_ref()); |
32 | 0 | } |
33 | 0 | for slice in protobuf::bytes_tag_encode(2, peer_id) { |
34 | 0 | out.extend_from_slice(slice.as_ref()); |
35 | 0 | } |
36 | 0 | out |
37 | 0 | } Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec8kademlia23build_find_node_request Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec8kademlia23build_find_node_request |
38 | | |
39 | | /// Decodes a response to a request built using [`build_find_node_request`]. |
40 | | // TODO: return a borrow of the response bytes ; we're limited by protobuf library |
41 | 0 | pub fn decode_find_node_response( |
42 | 0 | response_bytes: &[u8], |
43 | 0 | ) -> Result<Vec<(peer_id::PeerId, Vec<Vec<u8>>)>, DecodeFindNodeResponseError> { |
44 | 0 | let mut parser = nom::combinator::all_consuming::<_, _, nom::error::Error<&[u8]>, _>( |
45 | 0 | nom::combinator::complete(protobuf::message_decode! { |
46 | 0 | #[optional] response_ty = 1 => protobuf::enum_tag_decode, |
47 | 0 | #[repeated(max = 1024)] peers = 8 => protobuf::message_tag_decode(protobuf::message_decode!{ |
48 | 0 | #[required] peer_id = 1 => protobuf::bytes_tag_decode, |
49 | 0 | #[repeated(max = 1024)] addrs = 2 => protobuf::bytes_tag_decode, |
50 | 0 | }), Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec8kademlia25decode_find_node_responses_0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec8kademlia25decode_find_node_responses_0B9_ Unexecuted instantiation: _RNCNCNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec8kademlia25decode_find_node_responses_000Bd_ Unexecuted instantiation: _RNCNCNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec8kademlia25decode_find_node_responses_000Bd_ |
51 | 0 | }), |
52 | 0 | ); |
53 | | |
54 | 0 | let closer_peers = match nom::Finish::finish(parser(response_bytes)) { |
55 | 0 | Ok((_, out)) if out.response_ty.unwrap_or(0) == 4 => out.peers, |
56 | 0 | Ok((_, _)) => return Err(DecodeFindNodeResponseError::BadResponseTy), |
57 | | Err(_) => { |
58 | 0 | return Err(DecodeFindNodeResponseError::ProtobufDecode( |
59 | 0 | ProtobufDecodeError, |
60 | 0 | )) |
61 | | } |
62 | | }; |
63 | | |
64 | 0 | let mut result = Vec::with_capacity(closer_peers.len()); |
65 | 0 | for peer in closer_peers { |
66 | 0 | let peer_id = peer_id::PeerId::from_bytes(peer.peer_id.to_vec()) |
67 | 0 | .map_err(|(err, _)| DecodeFindNodeResponseError::BadPeerId(err))?; Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec8kademlia25decode_find_node_response0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec8kademlia25decode_find_node_response0B9_ |
68 | | |
69 | 0 | let mut multiaddrs = Vec::with_capacity(peer.addrs.len()); |
70 | 0 | for addr in peer.addrs { |
71 | 0 | multiaddrs.push(addr.to_vec()); |
72 | 0 | } |
73 | | |
74 | 0 | result.push((peer_id, multiaddrs)); |
75 | | } |
76 | | |
77 | 0 | Ok(result) |
78 | 0 | } Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec8kademlia25decode_find_node_response Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec8kademlia25decode_find_node_response |
79 | | |
80 | | /// Error potentially returned by [`decode_find_node_response`]. |
81 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs_NtNtNtCsN16ciHI6Qf_7smoldot7network5codec8kademliaNtB4_27DecodeFindNodeResponseErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs_NtNtNtCseuYC0Zibziv_7smoldot7network5codec8kademliaNtB4_27DecodeFindNodeResponseErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
82 | | pub enum DecodeFindNodeResponseError { |
83 | | /// Error while decoding the Protobuf encoding. |
84 | | #[display(fmt = "Error decoding the response: {_0}")] |
85 | | ProtobufDecode(ProtobufDecodeError), |
86 | | /// Response isn't a response to a find node request. |
87 | | BadResponseTy, |
88 | | /// Error while parsing a [`peer_id::PeerId`] in the response. |
89 | | #[display(fmt = "Invalid PeerId: {_0}")] |
90 | | BadPeerId(peer_id::FromBytesError), |
91 | | } |
92 | | |
93 | | /// Error while decoding the Protobuf encoding. |
94 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs1_NtNtNtCsN16ciHI6Qf_7smoldot7network5codec8kademliaNtB5_19ProtobufDecodeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs1_NtNtNtCseuYC0Zibziv_7smoldot7network5codec8kademliaNtB5_19ProtobufDecodeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
95 | | pub struct ProtobufDecodeError; |