1#![forbid(unsafe_code)]
17
18mod batch_certified;
19pub use batch_certified::BatchCertified;
20
21mod batch_propose;
22pub use batch_propose::BatchPropose;
23
24mod batch_signature;
25pub use batch_signature::BatchSignature;
26
27mod block_request;
28pub use block_request::BlockRequest;
29
30mod block_response;
31pub use block_response::{BlockResponse, DataBlocks};
32
33mod certificate_request;
34pub use certificate_request::CertificateRequest;
35
36mod certificate_response;
37pub use certificate_response::CertificateResponse;
38
39mod challenge_request;
40pub use challenge_request::ChallengeRequest;
41
42mod challenge_response;
43pub use challenge_response::ChallengeResponse;
44
45mod disconnect;
46pub use disconnect::{Disconnect, DisconnectReason};
47
48mod primary_ping;
49pub use primary_ping::PrimaryPing;
50
51mod transmission_request;
52pub use transmission_request::TransmissionRequest;
53
54mod transmission_response;
55pub use transmission_response::TransmissionResponse;
56
57mod validators_request;
58pub use validators_request::ValidatorsRequest;
59
60mod validators_response;
61pub use validators_response::ValidatorsResponse;
62
63mod worker_ping;
64pub use worker_ping::WorkerPing;
65
66use amareleo_node_sync::BlockLocators;
67use snarkvm::{
68 console::prelude::{FromBytes, Network, Read, ToBytes, Write, error},
69 ledger::{
70 block::Block,
71 narwhal::{BatchCertificate, BatchHeader, Data, Transmission, TransmissionID},
72 },
73 prelude::{Address, Field, Signature},
74};
75
76use anyhow::{Result, bail, ensure};
77use indexmap::{IndexMap, IndexSet};
78use serde::{Deserialize, Serialize};
79pub use std::io::{self, Result as IoResult};
80use std::{borrow::Cow, net::SocketAddr};
81
82pub trait EventTrait: ToBytes + FromBytes {
83 fn name(&self) -> Cow<'static, str>;
85}
86
87#[derive(Clone, Debug, PartialEq, Eq)]
88#[allow(clippy::large_enum_variant)]
91pub enum Event<N: Network> {
92 BatchPropose(BatchPropose<N>),
93 BatchSignature(BatchSignature<N>),
94 BatchCertified(BatchCertified<N>),
95 BlockRequest(BlockRequest),
96 BlockResponse(BlockResponse<N>),
97 CertificateRequest(CertificateRequest<N>),
98 CertificateResponse(CertificateResponse<N>),
99 ChallengeRequest(ChallengeRequest<N>),
100 ChallengeResponse(ChallengeResponse<N>),
101 Disconnect(Disconnect),
102 PrimaryPing(PrimaryPing<N>),
103 TransmissionRequest(TransmissionRequest<N>),
104 TransmissionResponse(TransmissionResponse<N>),
105 ValidatorsRequest(ValidatorsRequest),
106 ValidatorsResponse(ValidatorsResponse<N>),
107 WorkerPing(WorkerPing<N>),
108}
109
110impl<N: Network> From<DisconnectReason> for Event<N> {
111 fn from(reason: DisconnectReason) -> Self {
112 Self::Disconnect(Disconnect { reason })
113 }
114}
115
116impl<N: Network> Event<N> {
117 pub const VERSION: u32 = 8;
119
120 #[inline]
122 pub fn name(&self) -> Cow<'static, str> {
123 match self {
124 Self::BatchPropose(event) => event.name(),
125 Self::BatchSignature(event) => event.name(),
126 Self::BatchCertified(event) => event.name(),
127 Self::BlockRequest(event) => event.name(),
128 Self::BlockResponse(event) => event.name(),
129 Self::CertificateRequest(event) => event.name(),
130 Self::CertificateResponse(event) => event.name(),
131 Self::ChallengeRequest(event) => event.name(),
132 Self::ChallengeResponse(event) => event.name(),
133 Self::Disconnect(event) => event.name(),
134 Self::PrimaryPing(event) => event.name(),
135 Self::TransmissionRequest(event) => event.name(),
136 Self::TransmissionResponse(event) => event.name(),
137 Self::ValidatorsRequest(event) => event.name(),
138 Self::ValidatorsResponse(event) => event.name(),
139 Self::WorkerPing(event) => event.name(),
140 }
141 }
142
143 #[inline]
145 pub fn id(&self) -> u16 {
146 match self {
147 Self::BatchPropose(..) => 0,
148 Self::BatchSignature(..) => 1,
149 Self::BatchCertified(..) => 2,
150 Self::BlockRequest(..) => 3,
151 Self::BlockResponse(..) => 4,
152 Self::CertificateRequest(..) => 5,
153 Self::CertificateResponse(..) => 6,
154 Self::ChallengeRequest(..) => 7,
155 Self::ChallengeResponse(..) => 8,
156 Self::Disconnect(..) => 9,
157 Self::PrimaryPing(..) => 10,
158 Self::TransmissionRequest(..) => 11,
159 Self::TransmissionResponse(..) => 12,
160 Self::ValidatorsRequest(..) => 13,
161 Self::ValidatorsResponse(..) => 14,
162 Self::WorkerPing(..) => 15,
163 }
164 }
165}
166
167impl<N: Network> ToBytes for Event<N> {
168 fn write_le<W: io::Write>(&self, mut writer: W) -> IoResult<()> {
169 self.id().write_le(&mut writer)?;
170
171 match self {
172 Self::BatchPropose(event) => event.write_le(writer),
173 Self::BatchSignature(event) => event.write_le(writer),
174 Self::BatchCertified(event) => event.write_le(writer),
175 Self::BlockRequest(event) => event.write_le(writer),
176 Self::BlockResponse(event) => event.write_le(writer),
177 Self::CertificateRequest(event) => event.write_le(writer),
178 Self::CertificateResponse(event) => event.write_le(writer),
179 Self::ChallengeRequest(event) => event.write_le(writer),
180 Self::ChallengeResponse(event) => event.write_le(writer),
181 Self::Disconnect(event) => event.write_le(writer),
182 Self::PrimaryPing(event) => event.write_le(writer),
183 Self::TransmissionRequest(event) => event.write_le(writer),
184 Self::TransmissionResponse(event) => event.write_le(writer),
185 Self::ValidatorsRequest(event) => event.write_le(writer),
186 Self::ValidatorsResponse(event) => event.write_le(writer),
187 Self::WorkerPing(event) => event.write_le(writer),
188 }
189 }
190}
191
192impl<N: Network> FromBytes for Event<N> {
193 fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
194 let id = u16::read_le(&mut reader).map_err(|_| error("Unknown event ID"))?;
196
197 let event = match id {
199 0 => Self::BatchPropose(BatchPropose::read_le(&mut reader)?),
200 1 => Self::BatchSignature(BatchSignature::read_le(&mut reader)?),
201 2 => Self::BatchCertified(BatchCertified::read_le(&mut reader)?),
202 3 => Self::BlockRequest(BlockRequest::read_le(&mut reader)?),
203 4 => Self::BlockResponse(BlockResponse::read_le(&mut reader)?),
204 5 => Self::CertificateRequest(CertificateRequest::read_le(&mut reader)?),
205 6 => Self::CertificateResponse(CertificateResponse::read_le(&mut reader)?),
206 7 => Self::ChallengeRequest(ChallengeRequest::read_le(&mut reader)?),
207 8 => Self::ChallengeResponse(ChallengeResponse::read_le(&mut reader)?),
208 9 => Self::Disconnect(Disconnect::read_le(&mut reader)?),
209 10 => Self::PrimaryPing(PrimaryPing::read_le(&mut reader)?),
210 11 => Self::TransmissionRequest(TransmissionRequest::read_le(&mut reader)?),
211 12 => Self::TransmissionResponse(TransmissionResponse::read_le(&mut reader)?),
212 13 => Self::ValidatorsRequest(ValidatorsRequest::read_le(&mut reader)?),
213 14 => Self::ValidatorsResponse(ValidatorsResponse::read_le(&mut reader)?),
214 15 => Self::WorkerPing(WorkerPing::read_le(&mut reader)?),
215 16.. => return Err(error(format!("Unknown event ID {id}"))),
216 };
217
218 if reader.bytes().next().is_some() {
220 return Err(error("Leftover bytes in an Event"));
221 }
222
223 Ok(event)
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use crate::Event;
230 use bytes::{Buf, BufMut, BytesMut};
231 use snarkvm::console::prelude::{FromBytes, ToBytes};
232 type CurrentNetwork = snarkvm::prelude::MainnetV0;
233
234 #[test]
235 fn deserializing_invalid_data_panics() {
236 let buf = BytesMut::default();
237 let invalid_id = u16::MAX;
238 invalid_id.write_le(&mut buf.clone().writer()).unwrap();
239 assert_eq!(
240 Event::<CurrentNetwork>::read_le(buf.reader()).unwrap_err().to_string(),
241 format!("Unknown event ID")
242 );
243 }
244}
245
246#[cfg(test)]
247pub mod prop_tests {
248 use crate::{
249 Disconnect,
250 DisconnectReason,
251 Event,
252 batch_certified::prop_tests::any_batch_certified,
253 batch_propose::prop_tests::any_batch_propose,
254 batch_signature::prop_tests::any_batch_signature,
255 certificate_request::prop_tests::any_certificate_request,
256 certificate_response::prop_tests::any_certificate_response,
257 challenge_request::prop_tests::any_challenge_request,
258 challenge_response::prop_tests::any_challenge_response,
259 transmission_request::prop_tests::any_transmission_request,
260 transmission_response::prop_tests::any_transmission_response,
261 worker_ping::prop_tests::any_worker_ping,
262 };
263 use snarkvm::{
264 console::{network::Network, types::Field},
265 ledger::{narwhal::TransmissionID, puzzle::SolutionID},
266 prelude::{FromBytes, Rng, ToBytes, Uniform},
267 };
268
269 use proptest::{
270 prelude::{BoxedStrategy, Just, Strategy, any},
271 prop_oneof,
272 sample::Selector,
273 };
274 use test_strategy::proptest;
275
276 type CurrentNetwork = snarkvm::prelude::MainnetV0;
277
278 pub fn now() -> i64 {
280 time::OffsetDateTime::now_utc().unix_timestamp()
281 }
282
283 pub fn any_solution_id() -> BoxedStrategy<SolutionID<CurrentNetwork>> {
284 Just(0).prop_perturb(|_, mut rng| rng.gen::<u64>().into()).boxed()
285 }
286
287 pub fn any_transaction_id() -> BoxedStrategy<<CurrentNetwork as Network>::TransactionID> {
288 Just(0)
289 .prop_perturb(|_, mut rng| <CurrentNetwork as Network>::TransactionID::from(Field::rand(&mut rng)))
290 .boxed()
291 }
292
293 pub fn any_transmission_checksum() -> BoxedStrategy<<CurrentNetwork as Network>::TransmissionChecksum> {
294 Just(0).prop_perturb(|_, mut rng| rng.gen::<<CurrentNetwork as Network>::TransmissionChecksum>()).boxed()
295 }
296
297 pub fn any_transmission_id() -> BoxedStrategy<TransmissionID<CurrentNetwork>> {
298 prop_oneof![
299 (any_transaction_id(), any_transmission_checksum())
300 .prop_map(|(id, cs)| TransmissionID::Transaction(id, cs)),
301 (any_solution_id(), any_transmission_checksum()).prop_map(|(id, cs)| TransmissionID::Solution(id, cs)),
302 ]
303 .boxed()
304 }
305
306 pub fn any_event() -> BoxedStrategy<Event<CurrentNetwork>> {
307 prop_oneof![
308 any_batch_certified().prop_map(Event::BatchCertified),
309 any_batch_propose().prop_map(Event::BatchPropose),
310 any_batch_signature().prop_map(Event::BatchSignature),
311 any_certificate_request().prop_map(Event::CertificateRequest),
312 any_certificate_response().prop_map(Event::CertificateResponse),
313 any_challenge_request().prop_map(Event::ChallengeRequest),
314 any_challenge_response().prop_map(Event::ChallengeResponse),
315 (
316 Just(vec![
317 DisconnectReason::ProtocolViolation,
318 DisconnectReason::NoReasonGiven,
319 DisconnectReason::InvalidChallengeResponse,
320 DisconnectReason::OutdatedClientVersion,
321 ]),
322 any::<Selector>()
323 )
324 .prop_map(|(reasons, selector)| Event::Disconnect(Disconnect::from(selector.select(reasons)))),
325 any_transmission_request().prop_map(Event::TransmissionRequest),
326 any_transmission_response().prop_map(Event::TransmissionResponse),
327 any_worker_ping().prop_map(Event::WorkerPing)
328 ]
329 .boxed()
330 }
331
332 #[proptest]
333 fn serialize_deserialize(#[strategy(any_event())] original: Event<CurrentNetwork>) {
334 let mut buf = Vec::new();
335 Event::write_le(&original, &mut buf).unwrap();
336
337 let deserialized: Event<CurrentNetwork> = Event::read_le(&*buf).unwrap();
338 assert_eq!(original.id(), deserialized.id());
339 assert_eq!(original.name(), deserialized.name());
340 }
341}