snarkos_node_router_messages/
peer_response.rs1use super::*;
17
18use snarkvm::prelude::{FromBytes, ToBytes};
19
20use std::borrow::Cow;
21
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct PeerResponse {
24 pub peers: Vec<(SocketAddr, Option<u32>)>,
25}
26
27impl MessageTrait for PeerResponse {
28 #[inline]
30 fn name(&self) -> Cow<'static, str> {
31 "PeerResponse".into()
32 }
33}
34
35impl ToBytes for PeerResponse {
36 fn write_le<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
37 if self.peers.len() > u8::MAX as usize {
39 return Err(io::Error::new(io::ErrorKind::InvalidInput, format!("Too many peers: {}", self.peers.len())));
40 }
41
42 0u8.write_le(&mut writer)?;
46
47 (self.peers.len() as u8).write_le(&mut writer)?;
48 for (addr, height) in self.peers.iter() {
49 addr.write_le(&mut writer)?;
50 if let Some(h) = height {
51 1u8.write_le(&mut writer)?;
52 h.write_le(&mut writer)?;
53 } else {
54 0u8.write_le(&mut writer)?;
55 }
56 }
57 Ok(())
58 }
59}
60
61impl FromBytes for PeerResponse {
62 fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
63 let mut contains_heights = false;
71 let count_or_version = u8::read_le(&mut reader)?;
72 let count = if count_or_version == 0 {
73 contains_heights = true;
75 u8::read_le(&mut reader)?
77 } else {
78 count_or_version
80 };
81
82 let mut peers = Vec::with_capacity(count as usize);
83 for _ in 0..count {
84 let addr = SocketAddr::read_le(&mut reader)?;
85 let height = if contains_heights {
86 match u8::read_le(&mut reader)? {
87 1 => Some(u32::read_le(&mut reader)?),
88 0 => None,
89 _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid peer height".to_string())),
90 }
91 } else {
92 None
93 };
94 peers.push((addr, height));
95 }
96
97 Ok(Self { peers })
98 }
99}
100
101#[cfg(test)]
102pub mod prop_tests {
103 use crate::PeerResponse;
104 use snarkvm::utilities::{FromBytes, ToBytes};
105
106 use bytes::{Buf, BufMut, BytesMut};
107 use proptest::{
108 collection::vec,
109 prelude::{BoxedStrategy, Strategy, any},
110 };
111 use std::{
112 io,
113 net::{IpAddr, SocketAddr},
114 };
115 use test_strategy::proptest;
116
117 pub fn any_valid_socket_addr() -> BoxedStrategy<(SocketAddr, Option<u32>)> {
118 any::<(IpAddr, u16, Option<u32>)>()
119 .prop_map(|(ip_addr, port, height)| (SocketAddr::new(ip_addr, port), height))
120 .boxed()
121 }
122
123 pub fn any_vec() -> BoxedStrategy<Vec<(SocketAddr, Option<u32>)>> {
124 vec(any_valid_socket_addr(), 0..50).prop_map(|v| v).boxed()
125 }
126
127 pub fn any_peer_response() -> BoxedStrategy<PeerResponse> {
128 any_vec().prop_map(|peers| PeerResponse { peers }).boxed()
129 }
130
131 #[proptest]
132 fn peer_response_roundtrip(#[strategy(any_peer_response())] peer_response: PeerResponse) {
133 let mut bytes = BytesMut::default().writer();
134 peer_response.write_le(&mut bytes).unwrap();
135 let decoded = PeerResponse::read_le(&mut bytes.into_inner().reader()).unwrap();
136 assert_eq!(decoded, peer_response);
137 }
138
139 #[test]
141 fn empty_old_peerlist_handling() {
142 let serialized = &[0u8];
144 let deserialized = PeerResponse::read_le(&serialized[..]).unwrap_err();
145 assert_eq!(deserialized.kind(), io::ErrorKind::UnexpectedEof);
147 }
148}