fuel_block_committer_encoding/blob/
header.rs1use anyhow::{bail, Result};
2use bitvec::{field::BitField, order::Msb0, slice::BitSlice, vec::BitVec, view::BitView};
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5pub struct HeaderV1 {
6 pub bundle_id: u32,
7 pub num_bits: u32,
9 pub is_last: bool,
10 pub idx: u32,
11}
12
13impl HeaderV1 {
14 const BUNDLE_ID_BITS: usize = 32;
15 const NUM_BITS_BITS: usize = 21;
16 const IS_LAST_BITS: usize = 1;
17 const IDX_SIZE_BITS: usize = 17;
18 pub const TOTAL_SIZE_BITS: usize =
19 Self::BUNDLE_ID_BITS + Self::NUM_BITS_BITS + Self::IS_LAST_BITS + Self::IDX_SIZE_BITS;
20
21 fn encode(&self, buffer: &mut BitVec<u8, Msb0>) {
22 buffer.extend_from_bitslice(self.bundle_id.view_bits::<Msb0>());
23
24 buffer.extend_from_bitslice(&self.num_bits.view_bits::<Msb0>()[32 - Self::NUM_BITS_BITS..]);
25
26 buffer.push(self.is_last);
27
28 buffer.extend_from_bitslice(&self.idx.view_bits::<Msb0>()[32 - Self::IDX_SIZE_BITS..]);
29 }
30
31 fn decode(data: &BitSlice<u8, Msb0>) -> Result<(Self, usize)> {
32 if data.len() < Self::TOTAL_SIZE_BITS {
33 bail!(
34 "not enough data to decode header, expected {} bits, got {}",
35 Self::TOTAL_SIZE_BITS,
36 data.len()
37 )
38 }
39
40 let bundle_id = data[..Self::BUNDLE_ID_BITS].load_be();
41 let remaining_data = &data[Self::BUNDLE_ID_BITS..];
42
43 let num_bits = remaining_data[..Self::NUM_BITS_BITS].load_be::<u32>();
44 let remaining_data = &remaining_data[Self::NUM_BITS_BITS..];
45
46 let is_last = remaining_data[0];
47 let remaining_data = &remaining_data[1..];
48
49 let idx = remaining_data[..Self::IDX_SIZE_BITS].load_be::<u32>();
50 let remaining_data = &remaining_data[Self::IDX_SIZE_BITS..];
51
52 let header = Self {
53 bundle_id,
54 num_bits,
55 is_last,
56 idx,
57 };
58
59 let amount_read = data
60 .len()
61 .checked_sub(remaining_data.len())
62 .expect("remaining data to always be smaller than original data");
63
64 Ok((header, amount_read))
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Hash)]
69pub enum Header {
70 V1(HeaderV1),
71}
72
73impl Header {
74 const VERSION_BITS: usize = 16;
75 pub const V1_SIZE_BITS: usize = HeaderV1::TOTAL_SIZE_BITS + Self::VERSION_BITS;
76
77 pub(crate) fn encode(&self) -> BitVec<u8, Msb0> {
78 match self {
79 Self::V1(blob_header_v1) => {
80 let mut buffer = BitVec::<u8, Msb0>::new();
81
82 let version = 1u16;
83 buffer.extend_from_bitslice(version.view_bits::<Msb0>());
84
85 blob_header_v1.encode(&mut buffer);
86
87 buffer
88 }
89 }
90 }
91 pub(crate) fn decode(data: &BitSlice<u8, Msb0>) -> Result<(Self, usize)> {
92 if data.len() < Self::VERSION_BITS {
93 bail!(
94 "not enough data to decode header version, expected {} bits, got {}",
95 Self::VERSION_BITS,
96 data.len()
97 );
98 }
99
100 let version = data[..Self::VERSION_BITS].load_be::<u16>();
101
102 let remaining_data = &data[Self::VERSION_BITS..];
103 let read_version_bits = data
104 .len()
105 .checked_sub(remaining_data.len())
106 .expect("remaining_data should always be smaller than data");
107 match version {
108 1 => {
109 let (header, read_bits) = HeaderV1::decode(remaining_data)?;
110 Ok((
111 Self::V1(header),
112 read_bits
113 .checked_add(read_version_bits)
114 .expect("never to encode more than usize bits"),
115 ))
116 }
117 version => bail!("Unsupported version {version}"),
118 }
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use bitvec::{field::BitField, order::Msb0};
125
126 use super::Header;
127
128 #[test]
129 fn detects_unsupported_version() {
130 let mut encoded_header = Header::V1(super::HeaderV1 {
132 bundle_id: 0,
133 num_bits: 0,
134 is_last: false,
135 idx: 0,
136 })
137 .encode();
138
139 encoded_header[0..16].store_be(2u16);
140
141 let header = Header::decode(&encoded_header).unwrap_err();
143
144 assert_eq!(header.to_string(), "Unsupported version 2");
146 }
147
148 #[test]
149 fn complains_if_not_enough_data_is_given_for_version() {
150 let encoded_header = Header::V1(super::HeaderV1 {
152 bundle_id: 0,
153 num_bits: 0,
154 is_last: false,
155 idx: 0,
156 })
157 .encode();
158
159 let err = Header::decode(&encoded_header[..10]).unwrap_err();
161
162 assert_eq!(
164 err.to_string(),
165 "not enough data to decode header version, expected 16 bits, got 10"
166 );
167 }
168
169 #[test]
170 fn complains_if_not_enough_data_is_given_for_header() {
171 let encoded_header = Header::V1(super::HeaderV1 {
173 bundle_id: 0,
174 num_bits: 0,
175 is_last: false,
176 idx: 0,
177 })
178 .encode();
179
180 let err = Header::decode(&encoded_header[..18]).unwrap_err();
182
183 assert_eq!(
185 err.to_string(),
186 "not enough data to decode header, expected 71 bits, got 2"
187 );
188 }
189
190 #[test]
191 fn reports_correct_amount_read() {
192 let mut encoded_header = Header::V1(super::HeaderV1 {
194 bundle_id: 0,
195 num_bits: 0,
196 is_last: false,
197 idx: 0,
198 })
199 .encode();
200
201 encoded_header.extend_from_bitslice(&bitvec::bitvec![u8, Msb0; 0; 10]);
203
204 let (_, amount_read) = Header::decode(&encoded_header).unwrap();
206
207 assert_eq!(amount_read, 87);
209 }
210}