/ ledger / narwhal / batch-header / src / bytes.rs
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  }