zakura_network/zakura/block_sync/
wire.rs1use super::{config::*, error::*, *};
2
3pub const ZAKURA_STREAM_BLOCK_SYNC: u16 = 6;
5pub const ZAKURA_CAP_BLOCK_SYNC: u64 = 1 << 3;
7pub const ZAKURA_BLOCK_SYNC_STREAM_VERSION: u16 = 2;
9
10pub const MSG_BS_STATUS: u8 = 1;
12pub const MSG_BS_GET_BLOCKS: u8 = 2;
14pub const MSG_BS_BLOCK: u8 = 3;
16pub const MSG_BS_BLOCKS_DONE: u8 = 4;
18pub const MSG_BS_RANGE_UNAVAILABLE: u8 = 5;
20
21pub const MAX_BS_BLOCKS_PER_REQUEST: u32 = 128;
23pub const MAX_BS_MESSAGE_BYTES: usize = 3 * 1024 * 1024;
30
31pub(super) const BLOCK_SYNC_MESSAGE_TYPE_BYTES: usize = 1;
32
33const _: () = assert!(MAX_BS_MESSAGE_BYTES < 4 * 1024 * 1024);
34const _: () = assert!(MAX_BS_MESSAGE_BYTES > block::MAX_BLOCK_BYTES as usize);
35
36#[derive(Clone, Debug, Eq, PartialEq)]
38pub enum BlockSyncMessage {
39 Status(BlockSyncStatus),
41 GetBlocks {
43 start_height: block::Height,
45 count: u32,
47 },
48 Block(Arc<block::Block>),
50 BlocksDone {
52 start_height: block::Height,
54 returned: u32,
56 },
57 RangeUnavailable {
59 start_height: block::Height,
61 count: u32,
63 },
64}
65
66impl BlockSyncMessage {
67 pub fn message_type(&self) -> u8 {
69 match self {
70 Self::Status(_) => MSG_BS_STATUS,
71 Self::GetBlocks { .. } => MSG_BS_GET_BLOCKS,
72 Self::Block(_) => MSG_BS_BLOCK,
73 Self::BlocksDone { .. } => MSG_BS_BLOCKS_DONE,
74 Self::RangeUnavailable { .. } => MSG_BS_RANGE_UNAVAILABLE,
75 }
76 }
77
78 pub fn encode(&self) -> Result<Vec<u8>, BlockSyncWireError> {
80 let mut bytes = Vec::new();
81 bytes.write_u8(self.message_type())?;
82 match self {
83 Self::Status(status) => status.encode_to(&mut bytes)?,
84 Self::GetBlocks {
85 start_height,
86 count,
87 }
88 | Self::RangeUnavailable {
89 start_height,
90 count,
91 } => {
92 validate_block_count(*count)?;
93 write_height(&mut bytes, *start_height)?;
94 bytes.write_u32::<LittleEndian>(*count)?;
95 }
96 Self::Block(block) => {
97 block.zcash_serialize(&mut bytes)?;
98 validate_encoded_block_len(
99 bytes.len().saturating_sub(BLOCK_SYNC_MESSAGE_TYPE_BYTES),
100 )?;
101 }
102 Self::BlocksDone {
103 start_height,
104 returned,
105 } => {
106 validate_block_count(*returned)?;
107 write_height(&mut bytes, *start_height)?;
108 bytes.write_u32::<LittleEndian>(*returned)?;
109 }
110 }
111 validate_payload_len(bytes.len())?;
112 Ok(bytes)
113 }
114
115 pub fn decode(bytes: &[u8]) -> Result<Self, BlockSyncWireError> {
117 validate_payload_len(bytes.len())?;
118 let mut reader = Cursor::new(bytes);
119 let message_type = reader.read_u8()?;
120 let message = match message_type {
121 MSG_BS_STATUS => Self::Status(BlockSyncStatus::decode_from(&mut reader)?),
122 MSG_BS_GET_BLOCKS => {
123 let start_height = read_height(&mut reader)?;
124 let count = reader.read_u32::<LittleEndian>()?;
125 validate_block_count(count)?;
126 Self::GetBlocks {
127 start_height,
128 count,
129 }
130 }
131 MSG_BS_BLOCK => {
132 let block_start = usize::try_from(reader.position())
133 .map_err(|_| BlockSyncWireError::NumericOverflow("block payload offset"))?;
134 let block = Arc::new(block::Block::zcash_deserialize(&mut reader)?);
135 let block_end = usize::try_from(reader.position())
136 .map_err(|_| BlockSyncWireError::NumericOverflow("block payload end"))?;
137 validate_encoded_block_len(block_end.saturating_sub(block_start))?;
138 Self::Block(block)
139 }
140 MSG_BS_BLOCKS_DONE => {
141 let start_height = read_height(&mut reader)?;
142 let returned = reader.read_u32::<LittleEndian>()?;
143 validate_block_count(returned)?;
144 Self::BlocksDone {
145 start_height,
146 returned,
147 }
148 }
149 MSG_BS_RANGE_UNAVAILABLE => {
150 let start_height = read_height(&mut reader)?;
151 let count = reader.read_u32::<LittleEndian>()?;
152 validate_block_count(count)?;
153 Self::RangeUnavailable {
154 start_height,
155 count,
156 }
157 }
158 value => return Err(BlockSyncWireError::UnknownMessageType(value)),
159 };
160 reject_trailing(bytes, &reader)?;
161 Ok(message)
162 }
163
164 pub fn encode_frame(&self) -> Result<Frame, BlockSyncWireError> {
166 Ok(Frame {
167 message_type: u16::from(self.message_type()),
168 flags: 0,
169 payload: self.encode()?,
170 })
171 }
172
173 pub fn decode_frame(frame: Frame) -> Result<Self, BlockSyncWireError> {
175 Self::decode_frame_with_raw_block_payload(frame).map(|(message, _)| message)
176 }
177
178 pub(super) fn decode_frame_with_raw_block_payload(
185 frame: Frame,
186 ) -> Result<(Self, Option<Arc<[u8]>>), BlockSyncWireError> {
187 if frame.flags != 0 {
188 return Err(BlockSyncWireError::UnsupportedFlags(frame.flags));
189 }
190 let frame_message_type = u8::try_from(frame.message_type)
191 .map_err(|_| BlockSyncWireError::UnknownFrameMessageType(frame.message_type))?;
192
193 let (message, raw_block_payload) = if frame_message_type == MSG_BS_BLOCK {
196 let raw_block_payload = Arc::<[u8]>::from(frame.payload.into_boxed_slice());
197 let message = Self::decode(&raw_block_payload)?;
198 (message, Some(raw_block_payload))
199 } else {
200 (Self::decode(&frame.payload)?, None)
201 };
202
203 if frame_message_type != message.message_type() {
204 return Err(BlockSyncWireError::MismatchedFrameMessageType {
205 frame: frame.message_type,
206 payload: message.message_type(),
207 });
208 }
209 Ok((message, raw_block_payload))
210 }
211
212 pub(super) fn block_body_wire_bytes(&self, payload_len: usize) -> Option<u64> {
223 matches!(self, Self::Block(_)).then(|| {
224 u64::try_from(payload_len.saturating_sub(BLOCK_SYNC_MESSAGE_TYPE_BYTES))
225 .unwrap_or(u64::MAX)
226 })
227 }
228}
229
230pub(super) fn validate_block_count(count: u32) -> Result<(), BlockSyncWireError> {
231 if count == 0 {
232 return Err(BlockSyncWireError::ZeroBlockCount);
233 }
234 if count > MAX_BS_BLOCKS_PER_REQUEST {
235 return Err(BlockSyncWireError::BlockCountLimit {
236 actual: count,
237 max: MAX_BS_BLOCKS_PER_REQUEST,
238 });
239 }
240 Ok(())
241}
242
243pub(super) fn validate_payload_len(len: usize) -> Result<(), BlockSyncWireError> {
244 if len > MAX_BS_MESSAGE_BYTES {
245 return Err(BlockSyncWireError::OversizedPayload {
246 actual: len,
247 max: MAX_BS_MESSAGE_BYTES,
248 });
249 }
250 Ok(())
251}
252
253fn validate_encoded_block_len(len: usize) -> Result<(), BlockSyncWireError> {
254 let max = usize::try_from(block::MAX_BLOCK_BYTES)
255 .map_err(|_| BlockSyncWireError::NumericOverflow("max block bytes"))?;
256 if len > max {
257 return Err(BlockSyncWireError::OversizedBlock { actual: len, max });
258 }
259 Ok(())
260}
261
262pub(super) fn write_height<W: Write>(
263 writer: &mut W,
264 height: block::Height,
265) -> Result<(), BlockSyncWireError> {
266 writer.write_u32::<LittleEndian>(height.0)?;
267 Ok(())
268}
269
270pub(super) fn read_height<R: Read>(reader: &mut R) -> Result<block::Height, BlockSyncWireError> {
271 let raw = reader.read_u32::<LittleEndian>()?;
272 block::Height::try_from(raw).map_err(|_| BlockSyncWireError::HeightOutOfRange(raw))
273}
274
275pub(super) fn reject_trailing(
276 bytes: &[u8],
277 reader: &Cursor<&[u8]>,
278) -> Result<(), BlockSyncWireError> {
279 let consumed = usize::try_from(reader.position())
280 .map_err(|_| BlockSyncWireError::NumericOverflow("payload cursor"))?;
281 if consumed != bytes.len() {
282 return Err(BlockSyncWireError::TrailingBytes);
283 }
284 Ok(())
285}