snarkos_node_router_messages/
challenge_request.rs1use super::*;
17
18use snarkos_node_network::NodeType;
19use snarkvm::prelude::{FromBytes, ToBytes};
20
21use std::borrow::Cow;
22
23#[derive(Clone, Debug, PartialEq, Eq)]
24pub struct ChallengeRequest<N: Network> {
25 pub version: u32,
26 pub listener_port: u16,
27 pub node_type: NodeType,
28 pub address: Address<N>,
29 pub nonce: u64,
30 pub snarkos_sha: Option<String>,
31}
32
33impl<N: Network> MessageTrait for ChallengeRequest<N> {
34 #[inline]
36 fn name(&self) -> Cow<'static, str> {
37 "ChallengeRequest".into()
38 }
39}
40
41impl<N: Network> ToBytes for ChallengeRequest<N> {
42 fn write_le<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
43 self.version.write_le(&mut writer)?;
44 self.listener_port.write_le(&mut writer)?;
45 self.node_type.write_le(&mut writer)?;
46 self.address.write_le(&mut writer)?;
47 self.nonce.write_le(&mut writer)?;
48
49 if let Some(snarkos_sha) = &self.snarkos_sha {
50 snarkos_sha.as_bytes().write_le(&mut writer)?;
51 }
52
53 Ok(())
54 }
55}
56
57impl<N: Network> FromBytes for ChallengeRequest<N> {
58 fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
59 let version = u32::read_le(&mut reader)?;
60 let listener_port = u16::read_le(&mut reader)?;
61 let node_type = NodeType::read_le(&mut reader)?;
62 let address = Address::<N>::read_le(&mut reader)?;
63 let nonce = u64::read_le(&mut reader)?;
64 let snarkos_sha = str::from_utf8(&<[u8; 40]>::read_le(&mut reader).unwrap_or([b'?'; 40])[..])
65 .map(|str| if str.starts_with('?') { "unknown" } else { str })
66 .map_err(|_| error("Invalid snarkOS SHA"))?
67 .to_owned();
68
69 Ok(Self { version, listener_port, node_type, address, nonce, snarkos_sha: Some(snarkos_sha) })
70 }
71}
72
73impl<N: Network> ChallengeRequest<N> {
74 pub fn new(
75 listener_port: u16,
76 node_type: NodeType,
77 address: Address<N>,
78 nonce: u64,
79 snarkos_sha: Option<String>,
80 ) -> Self {
81 Self { version: Message::<N>::latest_message_version(), listener_port, node_type, address, nonce, snarkos_sha }
82 }
83}
84
85#[cfg(test)]
86pub mod prop_tests {
87 use crate::ChallengeRequest;
88 use snarkos_node_network::NodeType;
89 use snarkvm::{
90 console::prelude::{FromBytes, ToBytes},
91 prelude::{Address, TestRng, Uniform},
92 };
93
94 use bytes::{Buf, BufMut, BytesMut};
95 use proptest::{
96 collection,
97 prelude::{BoxedStrategy, Strategy, any},
98 };
99 use test_strategy::proptest;
100
101 type CurrentNetwork = snarkvm::prelude::MainnetV0;
102
103 pub fn any_valid_address() -> BoxedStrategy<Address<CurrentNetwork>> {
104 any::<u64>().prop_map(|seed| Address::rand(&mut TestRng::fixed(seed))).boxed()
105 }
106
107 pub fn any_node_type() -> BoxedStrategy<NodeType> {
108 (0..=2)
109 .prop_map(|id| match id {
110 0 => NodeType::Client,
111 1 => NodeType::Prover,
112 2 => NodeType::Validator,
113 _ => unreachable!(),
114 })
115 .boxed()
116 }
117
118 pub fn any_challenge_request() -> BoxedStrategy<ChallengeRequest<CurrentNetwork>> {
119 (any_valid_address(), any::<u64>(), any::<u32>(), any::<u16>(), any_node_type(), collection::vec(0u8..=127, 40))
120 .prop_map(|(address, nonce, version, listener_port, node_type, sha)| ChallengeRequest {
121 address,
122 nonce,
123 version,
124 listener_port,
125 node_type,
126 snarkos_sha: Some(sha.into_iter().map(|b| b as char).collect()),
127 })
128 .boxed()
129 }
130
131 #[proptest]
132 fn challenge_request_roundtrip(#[strategy(any_challenge_request())] original: ChallengeRequest<CurrentNetwork>) {
133 let mut buf = BytesMut::default().writer();
134 ChallengeRequest::write_le(&original, &mut buf).unwrap();
135
136 let mut deserialized: ChallengeRequest<CurrentNetwork> =
137 ChallengeRequest::read_le(buf.into_inner().reader()).unwrap();
138 if deserialized.snarkos_sha.as_ref().unwrap() == "unknown" {
140 deserialized.snarkos_sha = original.snarkos_sha.clone();
141 }
142 assert_eq!(original, deserialized);
143 }
144}