snarkos_node_router_messages/
lib.rs1#![forbid(unsafe_code)]
17
18#[macro_use]
19extern crate tracing;
20
21pub mod helpers;
22pub use helpers::*;
23
24mod block_request;
25pub use block_request::BlockRequest;
26
27mod block_response;
28pub use block_response::BlockResponse;
29
30mod challenge_request;
31pub use challenge_request::ChallengeRequest;
32
33mod challenge_response;
34pub use challenge_response::ChallengeResponse;
35
36mod disconnect;
37pub use disconnect::Disconnect;
38
39mod peer_request;
40pub use peer_request::PeerRequest;
41
42mod peer_response;
43pub use peer_response::PeerResponse;
44
45mod ping;
46pub use ping::Ping;
47
48mod pong;
49pub use pong::Pong;
50
51mod puzzle_request;
52pub use puzzle_request::PuzzleRequest;
53
54mod puzzle_response;
55pub use puzzle_response::PuzzleResponse;
56
57mod unconfirmed_solution;
58pub use unconfirmed_solution::UnconfirmedSolution;
59
60mod unconfirmed_transaction;
61pub use unconfirmed_transaction::UnconfirmedTransaction;
62
63pub use snarkos_node_bft_events::DataBlocks;
64
65use snarkos_node_sync_locators::BlockLocators;
66use snarkvm::prelude::{
67 Address,
68 ConsensusVersion,
69 FromBytes,
70 Network,
71 Signature,
72 ToBytes,
73 block::{Header, Transaction},
74 error,
75 puzzle::{Solution, SolutionID},
76};
77
78use std::{borrow::Cow, io, net::SocketAddr};
79
80pub trait MessageTrait: ToBytes + FromBytes {
81 fn name(&self) -> Cow<'static, str>;
83}
84
85#[derive(Clone, Debug, PartialEq, Eq)]
86pub enum Message<N: Network> {
87 BlockRequest(BlockRequest),
88 BlockResponse(BlockResponse<N>),
89 ChallengeRequest(ChallengeRequest<N>),
90 ChallengeResponse(ChallengeResponse<N>),
91 Disconnect(Disconnect),
92 PeerRequest(PeerRequest),
93 PeerResponse(PeerResponse),
94 Ping(Ping<N>),
95 Pong(Pong),
96 PuzzleRequest(PuzzleRequest),
97 PuzzleResponse(PuzzleResponse<N>),
98 UnconfirmedSolution(UnconfirmedSolution<N>),
99 UnconfirmedTransaction(UnconfirmedTransaction<N>),
100}
101
102impl<N: Network> From<DisconnectReason> for Message<N> {
103 fn from(reason: DisconnectReason) -> Self {
104 Self::Disconnect(Disconnect { reason })
105 }
106}
107
108impl<N: Network> Message<N> {
109 pub const VERSIONS: [(ConsensusVersion, u32); 7] = [
112 (ConsensusVersion::V5, 17),
113 (ConsensusVersion::V7, 18),
114 (ConsensusVersion::V8, 19),
115 (ConsensusVersion::V9, 20),
116 (ConsensusVersion::V10, 21),
117 (ConsensusVersion::V11, 22),
118 (ConsensusVersion::V12, 23),
119 ];
120
121 pub fn latest_message_version() -> u32 {
123 Self::VERSIONS.last().map(|(_, version)| *version).unwrap_or(0)
124 }
125
126 pub fn lowest_accepted_message_version(current_block_height: u32) -> u32 {
134 let latest_message_version = Self::latest_message_version();
136
137 let versions = Self::VERSIONS;
139
140 N::CONSENSUS_VERSION(current_block_height).map_or(latest_message_version, |seek_version| {
142 match versions.binary_search_by(|(version, _)| version.cmp(&seek_version)) {
144 Ok(index) => versions[index].1,
146 Err(index) => versions[index.saturating_sub(1)].1,
149 }
150 })
151 }
152
153 #[inline]
155 pub fn name(&self) -> Cow<'static, str> {
156 match self {
157 Self::BlockRequest(message) => message.name(),
158 Self::BlockResponse(message) => message.name(),
159 Self::ChallengeRequest(message) => message.name(),
160 Self::ChallengeResponse(message) => message.name(),
161 Self::Disconnect(message) => message.name(),
162 Self::PeerRequest(message) => message.name(),
163 Self::PeerResponse(message) => message.name(),
164 Self::Ping(message) => message.name(),
165 Self::Pong(message) => message.name(),
166 Self::PuzzleRequest(message) => message.name(),
167 Self::PuzzleResponse(message) => message.name(),
168 Self::UnconfirmedSolution(message) => message.name(),
169 Self::UnconfirmedTransaction(message) => message.name(),
170 }
171 }
172
173 #[inline]
175 pub fn id(&self) -> u16 {
176 match self {
177 Self::BlockRequest(..) => 0,
178 Self::BlockResponse(..) => 1,
179 Self::ChallengeRequest(..) => 2,
180 Self::ChallengeResponse(..) => 3,
181 Self::Disconnect(..) => 4,
182 Self::PeerRequest(..) => 5,
183 Self::PeerResponse(..) => 6,
184 Self::Ping(..) => 7,
185 Self::Pong(..) => 8,
186 Self::PuzzleRequest(..) => 9,
187 Self::PuzzleResponse(..) => 10,
188 Self::UnconfirmedSolution(..) => 11,
189 Self::UnconfirmedTransaction(..) => 12,
190 }
191 }
192
193 pub fn check_size(bytes: &[u8]) -> io::Result<()> {
195 let len = bytes.len();
197 if len < 2 {
198 return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid message"));
199 }
200
201 let id_bytes: [u8; 2] = (&bytes[..2])
203 .try_into()
204 .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "id couldn't be deserialized"))?;
205 let id = u16::from_le_bytes(id_bytes);
206
207 if id == 12 && len > N::MAX_TRANSACTION_SIZE {
209 return Err(io::Error::new(io::ErrorKind::InvalidData, "transaction is too large"))?;
210 }
211
212 Ok(())
213 }
214}
215
216impl<N: Network> ToBytes for Message<N> {
217 fn write_le<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
218 self.id().write_le(&mut writer)?;
219
220 match self {
221 Self::BlockRequest(message) => message.write_le(writer),
222 Self::BlockResponse(message) => message.write_le(writer),
223 Self::ChallengeRequest(message) => message.write_le(writer),
224 Self::ChallengeResponse(message) => message.write_le(writer),
225 Self::Disconnect(message) => message.write_le(writer),
226 Self::PeerRequest(message) => message.write_le(writer),
227 Self::PeerResponse(message) => message.write_le(writer),
228 Self::Ping(message) => message.write_le(writer),
229 Self::Pong(message) => message.write_le(writer),
230 Self::PuzzleRequest(message) => message.write_le(writer),
231 Self::PuzzleResponse(message) => message.write_le(writer),
232 Self::UnconfirmedSolution(message) => message.write_le(writer),
233 Self::UnconfirmedTransaction(message) => message.write_le(writer),
234 }
235 }
236}
237
238impl<N: Network> FromBytes for Message<N> {
239 fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
240 let mut id_bytes = [0u8; 2];
242 reader.read_exact(&mut id_bytes)?;
243 let id = u16::from_le_bytes(id_bytes);
244
245 let message = match id {
247 0 => Self::BlockRequest(BlockRequest::read_le(&mut reader)?),
248 1 => Self::BlockResponse(BlockResponse::read_le(&mut reader)?),
249 2 => Self::ChallengeRequest(ChallengeRequest::read_le(&mut reader)?),
250 3 => Self::ChallengeResponse(ChallengeResponse::read_le(&mut reader)?),
251 4 => Self::Disconnect(Disconnect::read_le(&mut reader)?),
252 5 => Self::PeerRequest(PeerRequest::read_le(&mut reader)?),
253 6 => Self::PeerResponse(PeerResponse::read_le(&mut reader)?),
254 7 => Self::Ping(Ping::read_le(&mut reader)?),
255 8 => Self::Pong(Pong::read_le(&mut reader)?),
256 9 => Self::PuzzleRequest(PuzzleRequest::read_le(&mut reader)?),
257 10 => Self::PuzzleResponse(PuzzleResponse::read_le(&mut reader)?),
258 11 => Self::UnconfirmedSolution(UnconfirmedSolution::read_le(&mut reader)?),
259 12 => Self::UnconfirmedTransaction(UnconfirmedTransaction::read_le(&mut reader)?),
260 13.. => return Err(error("Unknown message ID {id}")),
261 };
262
263 #[allow(clippy::unbuffered_bytes)]
265 if reader.bytes().next().is_some() {
266 return Err(error("Leftover bytes in a Message"));
267 }
268
269 Ok(message)
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276 use snarkvm::prelude::{CanaryV0, MainnetV0, TestnetV0};
277
278 fn consensus_constants_at_genesis<N: Network>() {
280 let height = 0;
281 let consensus_version = Message::<N>::lowest_accepted_message_version(height);
282 assert_eq!(consensus_version as usize, Message::<N>::VERSIONS.first().unwrap().1 as usize);
283 }
284
285 fn consensus_versions<N: Network>() {
287 let mut previous_version = Message::<N>::VERSIONS.first().unwrap().0;
288 for (version, _) in Message::<N>::VERSIONS.iter().skip(1) {
289 assert!(*version as usize > previous_version as usize);
290 previous_version = *version;
291 }
292 }
293
294 fn consensus_constants_increasing_heights<N: Network>() {
296 let mut previous_message_version = Message::<N>::VERSIONS.first().unwrap().1;
297 for (_, message_version) in Message::<N>::VERSIONS.iter().skip(1) {
298 assert_eq!(*message_version, previous_message_version + 1);
299 previous_message_version = *message_version;
300 }
301 }
302
303 #[test]
304 #[allow(clippy::assertions_on_constants)]
305 fn test_consensus_constants() {
306 consensus_constants_at_genesis::<MainnetV0>();
307 consensus_constants_at_genesis::<TestnetV0>();
308 consensus_constants_at_genesis::<CanaryV0>();
309
310 consensus_versions::<MainnetV0>();
311 consensus_versions::<TestnetV0>();
312 consensus_versions::<CanaryV0>();
313
314 consensus_constants_increasing_heights::<MainnetV0>();
315 consensus_constants_increasing_heights::<TestnetV0>();
316 consensus_constants_increasing_heights::<CanaryV0>();
317 }
318
319 #[test]
320 fn test_latest_consensus_version() {
321 let message_consensus_version = Message::<MainnetV0>::VERSIONS.last().unwrap().0;
322 let expected_consensus_version = MainnetV0::CONSENSUS_VERSION_HEIGHTS().last().unwrap().0;
323 assert_eq!(message_consensus_version, expected_consensus_version);
324
325 let message_consensus_version = Message::<TestnetV0>::VERSIONS.last().unwrap().0;
326 let expected_consensus_version = TestnetV0::CONSENSUS_VERSION_HEIGHTS().last().unwrap().0;
327 assert_eq!(message_consensus_version, expected_consensus_version);
328
329 let message_consensus_version = Message::<CanaryV0>::VERSIONS.last().unwrap().0;
330 let expected_consensus_version = CanaryV0::CONSENSUS_VERSION_HEIGHTS().last().unwrap().0;
331 assert_eq!(message_consensus_version, expected_consensus_version);
332 }
333}