snarkos_node_bft_events/
block_request.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::utilities::io_error;
19
20#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
21pub struct BlockRequest {
22    /// The starting block height (inclusive).
23    pub start_height: u32,
24    /// The ending block height (exclusive).
25    pub end_height: u32,
26}
27
28impl BlockRequest {
29    /// Creates a new block request and return an error if the range is not  well-formed.
30    pub fn new(start_height: u32, end_height: u32) -> IoResult<Self> {
31        if start_height == 0 {
32            Err(io_error("BlockRequest cannot include the genesis block"))
33        } else if start_height >= end_height {
34            Err(io_error(format!("BlockRequest must contain a valid range, but was {start_height}..{end_height}")))
35        } else {
36            Ok(Self { start_height, end_height })
37        }
38    }
39}
40
41impl EventTrait for BlockRequest {
42    /// Returns the event name.
43    #[inline]
44    fn name(&self) -> Cow<'static, str> {
45        let start = self.start_height;
46        let end = self.end_height;
47        match start + 1 == end {
48            true => format!("BlockRequest {start}"),
49            false => format!("BlockRequest {start}..{end}"),
50        }
51        .into()
52    }
53}
54
55impl ToBytes for BlockRequest {
56    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
57        self.start_height.write_le(&mut writer)?;
58        self.end_height.write_le(&mut writer)
59    }
60}
61
62impl FromBytes for BlockRequest {
63    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
64        let start_height = u32::read_le(&mut reader)?;
65        let end_height = u32::read_le(&mut reader)?;
66
67        Self::new(start_height, end_height)
68    }
69}
70
71#[cfg(test)]
72pub mod prop_tests {
73    use crate::{BlockRequest, DataBlocks};
74
75    use snarkvm::{
76        console::network::MainnetV0,
77        utilities::{FromBytes, ToBytes},
78    };
79
80    use bytes::{Buf, BufMut, BytesMut};
81    use proptest::prelude::prop_compose;
82    use test_strategy::proptest;
83
84    const MAX_RANGE: u32 = DataBlocks::<MainnetV0>::MAXIMUM_NUMBER_OF_BLOCKS as u32;
85
86    prop_compose! {
87        /// Creates a block request with a start point and a valid range.
88        pub fn any_block_request()(start_height in 1..u32::MAX-MAX_RANGE, num_blocks in 1..MAX_RANGE) -> BlockRequest {
89            BlockRequest { start_height, end_height: start_height + num_blocks }
90        }
91    }
92
93    #[proptest]
94    fn block_request_roundtrip(#[strategy(any_block_request())] block_request: BlockRequest) {
95        let mut bytes = BytesMut::default().writer();
96        block_request.write_le(&mut bytes).unwrap();
97        let decoded = BlockRequest::read_le(&mut bytes.into_inner().reader()).unwrap();
98        assert_eq![decoded, block_request];
99    }
100}