massa_protocol_exports/
bootstrap_peers.rs

1use crate::{PeerId, PeerIdDeserializer, PeerIdSerializer};
2use massa_models::serialization::{IpAddrDeserializer, IpAddrSerializer};
3use massa_serialization::{
4    Deserializer, SerializeError, Serializer, U16VarIntDeserializer, U16VarIntSerializer,
5    U32VarIntDeserializer, U32VarIntSerializer,
6};
7use nom::{
8    error::{context, ContextError, ParseError},
9    multi::length_count,
10    sequence::tuple,
11    IResult, Parser,
12};
13use peernet::transports::TransportType;
14use serde::{Deserialize, Serialize};
15use std::collections::HashMap;
16use std::net::SocketAddr;
17use std::ops::Bound::Included;
18
19/// Peer info provided in bootstrap
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct PeerData {
22    pub listeners: HashMap<SocketAddr, TransportType>,
23    pub category: String,
24}
25
26/// Peers that are transmitted during bootstrap
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28pub struct BootstrapPeers(pub Vec<(PeerId, HashMap<SocketAddr, TransportType>)>);
29
30/// Serializer for `BootstrapPeers`
31pub struct BootstrapPeersSerializer {
32    u32_serializer: U32VarIntSerializer,
33    ip_addr_serializer: IpAddrSerializer,
34    port_serializer: U16VarIntSerializer,
35    peer_id_serializer: PeerIdSerializer,
36}
37
38impl BootstrapPeersSerializer {
39    /// Creates a new `BootstrapPeersSerializer`
40    pub fn new() -> Self {
41        Self {
42            u32_serializer: U32VarIntSerializer::new(),
43            ip_addr_serializer: IpAddrSerializer::new(),
44            port_serializer: U16VarIntSerializer::new(),
45            peer_id_serializer: PeerIdSerializer::new(),
46        }
47    }
48}
49
50impl Default for BootstrapPeersSerializer {
51    fn default() -> Self {
52        Self::new()
53    }
54}
55
56impl Serializer<BootstrapPeers> for BootstrapPeersSerializer {
57    /// ```
58    /// use massa_protocol_exports::{BootstrapPeers, PeerId, TransportType, BootstrapPeersSerializer};
59    /// use massa_serialization::Serializer;
60    /// use massa_signature::KeyPair;
61    /// use std::collections::HashMap;
62    /// use std::str::FromStr;
63    ///
64    /// let keypair1 = KeyPair::generate(0).unwrap();
65    /// let mut peers = vec![];
66    /// let mut listeners1 = HashMap::default();
67    /// listeners1.insert("127.0.0.1:8080".parse().unwrap(), TransportType::Tcp);
68    /// peers.push((PeerId::from_public_key(keypair1.get_public_key()), listeners1));
69    /// let mut keypair2 = KeyPair::generate(0).unwrap();
70    /// let mut listeners2 = HashMap::default();
71    /// listeners2.insert("[::1]:8080".parse().unwrap(), TransportType::Tcp);
72    /// peers.push((PeerId::from_public_key(keypair1.get_public_key()), listeners2));
73    /// let mut serialized = Vec::new();
74    /// let peers = BootstrapPeers(peers);
75    /// let peers_serializer = BootstrapPeersSerializer::new();
76    /// peers_serializer.serialize(&peers, &mut serialized).unwrap();
77    /// ```
78    fn serialize(
79        &self,
80        value: &BootstrapPeers,
81        buffer: &mut Vec<u8>,
82    ) -> Result<(), SerializeError> {
83        let peers_count: u32 = value.0.len().try_into().map_err(|err| {
84            SerializeError::NumberTooBig(format!(
85                "too many peers blocks in BootstrapPeers: {}",
86                err
87            ))
88        })?;
89        self.u32_serializer.serialize(&peers_count, buffer)?;
90        for (peer_id, listeners) in value.0.iter() {
91            self.peer_id_serializer.serialize(peer_id, buffer)?;
92            self.u32_serializer
93                .serialize(&(listeners.len() as u32), buffer)?;
94            // Emit listeners in a deterministic order: `HashMap` iteration order is not
95            // stable, so without sorting, logically identical peer sets could produce
96            // different byte encodings (a non-canonical format). Sorting by socket
97            // address (unique per map) yields a canonical, reproducible encoding.
98            let mut listeners: Vec<(&SocketAddr, &TransportType)> = listeners.iter().collect();
99            listeners.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
100            for (addr, transport_type) in listeners {
101                self.ip_addr_serializer.serialize(&addr.ip(), buffer)?;
102                self.port_serializer.serialize(&addr.port(), buffer)?;
103                buffer.push(*transport_type as u8);
104            }
105        }
106        Ok(())
107    }
108}
109
110/// Deserializer for `BootstrapPeers`
111pub struct BootstrapPeersDeserializer {
112    length_deserializer: U32VarIntDeserializer,
113    length_listeners_deserializer: U32VarIntDeserializer,
114    ip_addr_deserializer: IpAddrDeserializer,
115    port_deserializer: U16VarIntDeserializer,
116    peer_id_deserializer: PeerIdDeserializer,
117}
118
119impl BootstrapPeersDeserializer {
120    /// Creates a new `BootstrapPeersDeserializer`
121    ///
122    /// Arguments:
123    ///
124    /// * `max_peers`: maximum peers that can be serialized
125    pub fn new(max_peers: u32, max_listeners_per_peer: u32) -> Self {
126        Self {
127            length_deserializer: U32VarIntDeserializer::new(Included(0), Included(max_peers)),
128            length_listeners_deserializer: U32VarIntDeserializer::new(
129                Included(0),
130                Included(max_listeners_per_peer),
131            ),
132            ip_addr_deserializer: IpAddrDeserializer::new(),
133            port_deserializer: U16VarIntDeserializer::new(Included(0), Included(u16::MAX)),
134            peer_id_deserializer: PeerIdDeserializer::new(),
135        }
136    }
137}
138
139impl Deserializer<BootstrapPeers> for BootstrapPeersDeserializer {
140    /// ```
141    /// use massa_protocol_exports::{BootstrapPeers, PeerId, TransportType, BootstrapPeersSerializer, BootstrapPeersDeserializer};
142    /// use massa_serialization::{Serializer, Deserializer, DeserializeError};
143    /// use massa_signature::KeyPair;
144    /// use std::collections::HashMap;
145    /// use std::str::FromStr;
146    ///
147    /// let keypair1 = KeyPair::generate(0).unwrap();
148    /// let mut peers = vec![];
149    /// let mut listeners1 = HashMap::default();
150    /// listeners1.insert("127.0.0.1:8080".parse().unwrap(), TransportType::Tcp);
151    /// peers.push((PeerId::from_public_key(keypair1.get_public_key()), listeners1));
152    /// let mut keypair2 = KeyPair::generate(0).unwrap();
153    /// let mut listeners2 = HashMap::default();
154    /// listeners2.insert("[::1]:8080".parse().unwrap(), TransportType::Tcp);
155    /// peers.push((PeerId::from_public_key(keypair1.get_public_key()), listeners2));
156    /// let mut serialized = Vec::new();
157    /// let peers = BootstrapPeers(peers);
158    /// let peers_serializer = BootstrapPeersSerializer::new();
159    /// peers_serializer.serialize(&peers, &mut serialized).unwrap();
160    /// let peers_deserializer = BootstrapPeersDeserializer::new(10, 10);
161    /// let (rest, peers) = peers_deserializer.deserialize::<DeserializeError>(&serialized).unwrap();
162    /// assert!(rest.is_empty());
163    /// assert_eq!(peers, peers);
164    /// ```
165    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
166        &self,
167        buffer: &'a [u8],
168    ) -> IResult<&'a [u8], BootstrapPeers, E> {
169        length_count(
170            context("Failed length deserialization", |input| {
171                self.length_deserializer.deserialize(input)
172            }),
173            context("Failed Peer deserialization", |input| {
174                tuple((
175                    context("Failed PeerId deserialization", |input: &'a [u8]| {
176                        self.peer_id_deserializer.deserialize(input)
177                    }),
178                    length_count(
179                        context("Failed length deserialization", |input| {
180                            self.length_listeners_deserializer.deserialize(input)
181                        }),
182                        context("Failed listener deserialization", |buffer: &'a [u8]| {
183                            tuple((
184                                tuple((
185                                    context("Failed ip deserialization", |buffer| {
186                                        self.ip_addr_deserializer.deserialize(buffer)
187                                    }),
188                                    context("Failed port deserialization", |buffer| {
189                                        self.port_deserializer.deserialize(buffer)
190                                    }),
191                                ))
192                                .map(|(addr, ip)| SocketAddr::new(addr, ip)),
193                                context("Failed transport deserialization", |buffer| {
194                                    let (rest, id) = nom::number::complete::be_u8(buffer)?;
195                                    match id {
196                                        0 => Ok((rest, TransportType::Tcp)),
197                                        1 => Ok((rest, TransportType::Quic)),
198                                        _ => Err(nom::Err::Error(ParseError::from_error_kind(
199                                            buffer,
200                                            nom::error::ErrorKind::MapRes,
201                                        ))),
202                                    }
203                                }),
204                            ))
205                            .parse(buffer)
206                        }),
207                    )
208                    .map(|listeners| {
209                        listeners
210                            .into_iter()
211                            .collect::<HashMap<SocketAddr, TransportType>>()
212                    }),
213                ))
214                .parse(input)
215            }),
216        )
217        .map(BootstrapPeers)
218        .parse(buffer)
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225    use massa_serialization::DeserializeError;
226    use massa_signature::KeyPair;
227
228    fn peer_id() -> PeerId {
229        PeerId::from_public_key(KeyPair::generate(0).unwrap().get_public_key())
230    }
231
232    /// Logically identical `BootstrapPeers` (same listeners, different insertion
233    /// order) must serialize to the exact same bytes: the format is canonical.
234    #[test]
235    fn serialization_is_canonical_regardless_of_insertion_order() {
236        let id = peer_id();
237
238        let mut listeners_a = HashMap::default();
239        listeners_a.insert("127.0.0.1:8080".parse().unwrap(), TransportType::Tcp);
240        listeners_a.insert("127.0.0.1:8081".parse().unwrap(), TransportType::Quic);
241        listeners_a.insert("[::1]:8082".parse().unwrap(), TransportType::Tcp);
242
243        // same set, inserted in the opposite order
244        let mut listeners_b = HashMap::default();
245        listeners_b.insert("[::1]:8082".parse().unwrap(), TransportType::Tcp);
246        listeners_b.insert("127.0.0.1:8081".parse().unwrap(), TransportType::Quic);
247        listeners_b.insert("127.0.0.1:8080".parse().unwrap(), TransportType::Tcp);
248
249        let peers_a = BootstrapPeers(vec![(id, listeners_a)]);
250        let peers_b = BootstrapPeers(vec![(id, listeners_b)]);
251
252        let serializer = BootstrapPeersSerializer::new();
253        let mut buf_a = Vec::new();
254        let mut buf_b = Vec::new();
255        serializer.serialize(&peers_a, &mut buf_a).unwrap();
256        serializer.serialize(&peers_b, &mut buf_b).unwrap();
257
258        assert_eq!(buf_a, buf_b);
259    }
260
261    /// A serialize -> deserialize -> serialize cycle is byte-stable.
262    #[test]
263    fn serialize_deserialize_serialize_is_stable() {
264        let id = peer_id();
265        let mut listeners = HashMap::default();
266        listeners.insert("127.0.0.1:8080".parse().unwrap(), TransportType::Tcp);
267        listeners.insert("127.0.0.1:8081".parse().unwrap(), TransportType::Quic);
268        listeners.insert("[::1]:8082".parse().unwrap(), TransportType::Tcp);
269        let peers = BootstrapPeers(vec![(id, listeners)]);
270
271        let serializer = BootstrapPeersSerializer::new();
272        let deserializer = BootstrapPeersDeserializer::new(10, 10);
273
274        let mut buf1 = Vec::new();
275        serializer.serialize(&peers, &mut buf1).unwrap();
276        let (rest, deserialized) = deserializer.deserialize::<DeserializeError>(&buf1).unwrap();
277        assert!(rest.is_empty());
278        assert_eq!(peers, deserialized);
279
280        let mut buf2 = Vec::new();
281        serializer.serialize(&deserialized, &mut buf2).unwrap();
282        assert_eq!(buf1, buf2);
283    }
284}