bytes.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the alphavm 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 16 use super::*; 17 18 impl<N: Network> FromBytes for BatchHeader<N> { 19 /// Read the batch header either with or without checks on 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 batch header version")); 26 } 27 28 // Read the batch ID. 29 let batch_id = Field::read_le(&mut reader)?; 30 // Read the author. 31 let author = Address::read_le(&mut reader)?; 32 // Read the round number. 33 let round = u64::read_le(&mut reader)?; 34 // Read the timestamp. 35 let timestamp = i64::read_le(&mut reader)?; 36 // Read the committee ID. 37 let committee_id = Field::read_le(&mut reader)?; 38 39 // Read the number of transmission IDs. 40 let num_transmission_ids = u32::read_le(&mut reader)?; 41 // Ensure the number of transmission IDs is within bounds. 42 if num_transmission_ids as usize > Self::MAX_TRANSMISSIONS_PER_BATCH { 43 return Err(error(format!( 44 "Number of transmission IDs ({num_transmission_ids}) exceeds the maximum ({})", 45 Self::MAX_TRANSMISSIONS_PER_BATCH, 46 ))); 47 } 48 // Read the transmission IDs. 49 let mut transmission_ids = IndexSet::new(); 50 for _ in 0..num_transmission_ids { 51 // Insert the transmission ID. 52 transmission_ids.insert(TransmissionID::read_le(&mut reader)?); 53 } 54 55 // Read the number of previous certificate IDs. 56 let num_previous_certificate_ids = u16::read_le(&mut reader)?; 57 // Ensure the number of previous certificate IDs is within bounds. 58 if num_previous_certificate_ids > N::LATEST_MAX_CERTIFICATES().map_err(io_error)? { 59 return Err(error(format!( 60 "Number of previous certificate IDs ({num_previous_certificate_ids}) exceeds the maximum.", 61 ))); 62 } 63 64 // Read the previous certificate ID bytes. 65 let mut previous_certificate_id_bytes = 66 vec![0u8; num_previous_certificate_ids as usize * Field::<N>::size_in_bytes()]; 67 reader.read_exact(&mut previous_certificate_id_bytes)?; 68 // Read the previous certificate IDs. 69 let previous_certificate_ids = cfg_chunks!(previous_certificate_id_bytes, Field::<N>::size_in_bytes()) 70 .map(Field::read_le) 71 .collect::<Result<IndexSet<_>, _>>()?; 72 73 // Read the signature. 74 75 // Construct the batch. 76 let batch = if unchecked { 77 let signature = Signature::read_le_unchecked(&mut reader)?; 78 Self::from_unchecked( 79 author, 80 batch_id, 81 round, 82 timestamp, 83 committee_id, 84 transmission_ids, 85 previous_certificate_ids, 86 signature, 87 ) 88 } else { 89 let signature = Signature::read_le(&mut reader)?; 90 Self::from(author, round, timestamp, committee_id, transmission_ids, previous_certificate_ids, signature) 91 .map_err(io_error)? 92 }; 93 94 // Return the batch. 95 match batch.batch_id == batch_id { 96 true => Ok(batch), 97 false => Err(error("Invalid batch ID")), 98 } 99 } 100 101 /// Reads the batch header from the buffer. 102 fn read_le<R: Read>(reader: R) -> IoResult<Self> { 103 Self::read_le_with_unchecked(reader, false) 104 } 105 106 /// Reads the batch header from the buffer *without* performing any checks 107 /// for consistency/correctness. 108 fn read_le_unchecked<R: Read>(reader: R) -> IoResult<Self> { 109 Self::read_le_with_unchecked(reader, true) 110 } 111 } 112 113 impl<N: Network> ToBytes for BatchHeader<N> { 114 /// Writes the batch header to the buffer. 115 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> { 116 // Write the version. 117 1u8.write_le(&mut writer)?; 118 // Write the batch ID. 119 self.batch_id.write_le(&mut writer)?; 120 // Write the author. 121 self.author.write_le(&mut writer)?; 122 // Write the round number. 123 self.round.write_le(&mut writer)?; 124 // Write the timestamp. 125 self.timestamp.write_le(&mut writer)?; 126 // Write the committee ID. 127 self.committee_id.write_le(&mut writer)?; 128 // Write the number of transmission IDs. 129 u32::try_from(self.transmission_ids.len()).map_err(|e| error(e.to_string()))?.write_le(&mut writer)?; 130 // Write the transmission IDs. 131 for transmission_id in &self.transmission_ids { 132 // Write the transmission ID. 133 transmission_id.write_le(&mut writer)?; 134 } 135 // Write the number of previous certificate IDs. 136 u16::try_from(self.previous_certificate_ids.len()).map_err(|e| error(e.to_string()))?.write_le(&mut writer)?; 137 // Write the previous certificate IDs. 138 for certificate_id in &self.previous_certificate_ids { 139 // Write the certificate ID. 140 certificate_id.write_le(&mut writer)?; 141 } 142 // Write the signature. 143 self.signature.write_le(&mut writer) 144 } 145 } 146 147 #[cfg(test)] 148 mod tests { 149 use super::*; 150 151 #[test] 152 fn test_bytes() { 153 let rng = &mut TestRng::default(); 154 155 for expected in crate::test_helpers::sample_batch_headers(rng) { 156 // Check the byte representation. 157 let expected_bytes = expected.to_bytes_le().unwrap(); 158 assert_eq!(expected, BatchHeader::read_le(&expected_bytes[..]).unwrap()); 159 assert_eq!(expected, BatchHeader::read_le_unchecked(&expected_bytes[..]).unwrap()); 160 } 161 } 162 }