snarkos_node_router_messages/
block_response.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkOS library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18use snarkvm::{
19    ledger::narwhal::Data,
20    prelude::{FromBytes, ToBytes},
21};
22
23use std::borrow::Cow;
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct BlockResponse<N: Network> {
27    /// The original block request.
28    pub request: BlockRequest,
29    /// The blocks.
30    pub blocks: Data<DataBlocks<N>>,
31}
32
33impl<N: Network> MessageTrait for BlockResponse<N> {
34    /// Returns the message name.
35    #[inline]
36    fn name(&self) -> Cow<'static, str> {
37        let start = self.request.start_height;
38        let end = self.request.end_height;
39        match start + 1 == end {
40            true => format!("BlockResponse {start}"),
41            false => format!("BlockResponse {start}..{end}"),
42        }
43        .into()
44    }
45}
46
47impl<N: Network> ToBytes for BlockResponse<N> {
48    fn write_le<W: io::Write>(&self, mut writer: W) -> io::Result<()> {
49        self.request.write_le(&mut writer)?;
50        self.blocks.write_le(writer)
51    }
52}
53
54impl<N: Network> FromBytes for BlockResponse<N> {
55    fn read_le<R: io::Read>(mut reader: R) -> io::Result<Self> {
56        let request = BlockRequest::read_le(&mut reader)?;
57        let blocks = Data::read_le(reader)?;
58        Ok(Self { request, blocks })
59    }
60}
61
62#[cfg(test)]
63pub mod prop_tests {
64    use crate::{BlockResponse, DataBlocks, block_request::prop_tests::any_block_request};
65    use snarkvm::{
66        ledger::test_helpers::sample_genesis_block,
67        prelude::{block::Block, narwhal::Data},
68        utilities::{FromBytes, TestRng, ToBytes},
69    };
70
71    use bytes::{Buf, BufMut, BytesMut};
72    use proptest::{
73        collection::vec,
74        prelude::{BoxedStrategy, Strategy, any},
75    };
76    use test_strategy::proptest;
77
78    type CurrentNetwork = snarkvm::prelude::MainnetV0;
79
80    pub fn any_block() -> BoxedStrategy<Block<CurrentNetwork>> {
81        any::<u64>().prop_map(|seed| sample_genesis_block(&mut TestRng::fixed(seed))).boxed()
82    }
83
84    pub fn any_data_blocks() -> BoxedStrategy<DataBlocks<CurrentNetwork>> {
85        vec(any_block(), 0..=1).prop_map(DataBlocks).boxed()
86    }
87
88    pub fn any_block_response() -> BoxedStrategy<BlockResponse<CurrentNetwork>> {
89        (any_block_request(), any_data_blocks())
90            .prop_map(|(request, data_blocks)| BlockResponse { request, blocks: Data::Object(data_blocks) })
91            .boxed()
92    }
93
94    #[proptest]
95    fn block_response_roundtrip(#[strategy(any_block_response())] block_response: BlockResponse<CurrentNetwork>) {
96        let mut bytes = BytesMut::default().writer();
97        block_response.write_le(&mut bytes).unwrap();
98        let decoded = BlockResponse::<CurrentNetwork>::read_le(&mut bytes.into_inner().reader()).unwrap();
99        assert_eq!(block_response.request, decoded.request);
100        assert_eq!(
101            block_response.blocks.deserialize_blocking().unwrap(),
102            decoded.blocks.deserialize_blocking().unwrap(),
103        );
104    }
105}