snarkvm_ledger_block/
bytes.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM 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
18impl<N: Network> FromBytes for Block<N> {
19    /// Read the block either with or without checking the data.
20    fn read_le_with_unchecked<R: Read>(mut reader: R, unchecked: bool) -> IoResult<Self> {
21        // Read the version.
22        let version = u8::read_le(&mut reader)?;
23        // Ensure the version is valid.
24        if version != 1 {
25            return Err(error("Invalid block version"));
26        }
27
28        // Read the block hash.
29        let block_hash: N::BlockHash = FromBytes::read_le_with_unchecked(&mut reader, unchecked)?;
30        // Read the previous block hash.
31        let previous_hash = FromBytes::read_le_with_unchecked(&mut reader, unchecked)?;
32        // Read the header.
33        let header = FromBytes::read_le_with_unchecked(&mut reader, unchecked)?;
34
35        // Read the authority.
36        let authority = Authority::<N>::read_le_with_unchecked(&mut reader, unchecked)?;
37
38        // Read the ratifications.
39        let ratifications = Ratifications::read_le_with_unchecked(&mut reader, unchecked)?;
40
41        // Read the solutions.
42        let solutions: Solutions<N> = FromBytes::read_le_with_unchecked(&mut reader, unchecked)?;
43
44        // Read the number of aborted solution IDs.
45        let num_aborted_solutions = u32::read_le(&mut reader)?;
46        // Ensure the number of aborted solutions IDs is within bounds (this is an early safety check).
47        if num_aborted_solutions as usize > Solutions::<N>::max_aborted_solutions().map_err(error)? {
48            return Err(error("Invalid number of aborted solutions IDs in the block"));
49        }
50        // Read the aborted solution IDs.
51        let mut aborted_solution_ids = Vec::with_capacity(num_aborted_solutions as usize);
52        for _ in 0..num_aborted_solutions {
53            aborted_solution_ids.push(FromBytes::read_le_with_unchecked(&mut reader, unchecked)?);
54        }
55
56        // Read the transactions.
57        let transactions = FromBytes::read_le_with_unchecked(&mut reader, unchecked)?;
58
59        // Read the number of aborted transaction IDs.
60        let num_aborted_transactions = u32::read_le(&mut reader)?;
61        // Ensure the number of aborted transaction IDs is within bounds (this is an early safety check).
62        if num_aborted_transactions as usize > Transactions::<N>::max_aborted_transactions().map_err(error)? {
63            return Err(error("Invalid number of aborted transaction IDs in the block"));
64        }
65        // Read the aborted transaction IDs.
66        let mut aborted_transaction_ids = Vec::with_capacity(num_aborted_transactions as usize);
67        for _ in 0..num_aborted_transactions {
68            aborted_transaction_ids.push(FromBytes::read_le_with_unchecked(&mut reader, unchecked)?);
69        }
70
71        // Construct the block.
72        let block = if unchecked {
73            Self::from_unchecked(
74                block_hash,
75                previous_hash,
76                header,
77                authority,
78                ratifications,
79                solutions,
80                aborted_solution_ids,
81                transactions,
82                aborted_transaction_ids,
83            )
84        } else {
85            Self::from(
86                previous_hash,
87                header,
88                authority,
89                ratifications,
90                solutions,
91                aborted_solution_ids,
92                transactions,
93                aborted_transaction_ids,
94            )
95        }
96        .map_err(error)?;
97
98        // Ensure the block hash matches.
99        match block_hash == block.hash() {
100            true => Ok(block),
101            false => Err(error("Mismatching block hash, possible data corruption")),
102        }
103    }
104
105    /// Reads the block from the buffer.
106    fn read_le<R: Read>(reader: R) -> IoResult<Self> {
107        Self::read_le_with_unchecked(reader, false)
108    }
109
110    // Reads the block from the buffer without any checks on the data.
111    fn read_le_unchecked<R: Read>(reader: R) -> IoResult<Self> {
112        Self::read_le_with_unchecked(reader, true)
113    }
114}
115
116impl<N: Network> ToBytes for Block<N> {
117    /// Writes the block to the buffer.
118    #[inline]
119    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
120        // Write the version.
121        1u8.write_le(&mut writer)?;
122
123        // Write the block hash.
124        self.block_hash.write_le(&mut writer)?;
125        // Write the previous block hash.
126        self.previous_hash.write_le(&mut writer)?;
127        // Write the header.
128        self.header.write_le(&mut writer)?;
129
130        // Write the authority.
131        self.authority.write_le(&mut writer)?;
132
133        // Write the ratifications.
134        self.ratifications.write_le(&mut writer)?;
135
136        // Write the solutions.
137        self.solutions.write_le(&mut writer)?;
138
139        // Write the aborted solution IDs.
140        (u32::try_from(self.aborted_solution_ids.len()).map_err(error))?.write_le(&mut writer)?;
141        self.aborted_solution_ids.write_le(&mut writer)?;
142
143        // Write the transactions.
144        self.transactions.write_le(&mut writer)?;
145
146        // Write the aborted transaction IDs.
147        (u32::try_from(self.aborted_transaction_ids.len()).map_err(error))?.write_le(&mut writer)?;
148        self.aborted_transaction_ids.write_le(&mut writer)
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155    use console::network::MainnetV0;
156
157    type CurrentNetwork = MainnetV0;
158
159    #[test]
160    fn test_bytes() -> Result<()> {
161        let rng = &mut TestRng::default();
162
163        for expected in [crate::test_helpers::sample_genesis_block(rng)].into_iter() {
164            // Check the byte representation.
165            let expected_bytes = expected.to_bytes_le()?;
166            assert_eq!(expected, Block::read_le(&expected_bytes[..])?);
167            assert_eq!(expected, Block::read_le_unchecked(&expected_bytes[..])?);
168        }
169        Ok(())
170    }
171
172    #[test]
173    fn test_genesis_bytes() -> Result<()> {
174        // Load the genesis block.
175        let genesis_block = Block::<CurrentNetwork>::read_le(CurrentNetwork::genesis_bytes()).unwrap();
176
177        // Check the byte representation.
178        let expected_bytes = genesis_block.to_bytes_le()?;
179        assert_eq!(genesis_block, Block::read_le(&expected_bytes[..])?);
180        assert_eq!(genesis_block, Block::read_le_unchecked(&expected_bytes[..])?);
181
182        Ok(())
183    }
184
185    #[test]
186    fn test_bincode() -> Result<()> {
187        // Load the genesis block.
188        let genesis_block = Block::<CurrentNetwork>::read_le(CurrentNetwork::genesis_bytes()).unwrap();
189
190        let bincode_data = bincode::serialize(&genesis_block)?;
191        let block = bincode::deserialize(&bincode_data)?;
192
193        assert_eq!(genesis_block, block);
194
195        Ok(())
196    }
197}