fuel_block_committer_encoding/blob/
decoder.rs1use std::marker::PhantomData;
2
3use bitvec::{order::Msb0, slice::BitSlice, vec::BitVec};
4
5use super::{header::Header, Blob};
6mod validator;
7
8#[derive(Default, Debug, Clone)]
9pub struct Decoder {
10 _private: PhantomData<()>,
11}
12
13impl Decoder {
14 pub fn decode(&self, blobs: &[Blob]) -> anyhow::Result<Vec<u8>> {
15 let blobs = validator::Validator::for_blobs(blobs)?;
16
17 let data = {
18 let mut data_bits = BitVec::<u8, Msb0>::new();
19
20 for blob in blobs.validated_blobs()? {
21 let mut field_element_data = blob.chunks(256).map(|chunk| &chunk[2..]);
22
23 let first_chunk = field_element_data.next();
24
25 if let Some(chunk) = first_chunk {
26 data_bits.extend_from_bitslice(&chunk[Header::V1_SIZE_BITS..]);
27 }
28
29 for chunk in field_element_data {
30 data_bits.extend_from_bitslice(chunk);
31 }
32 }
33
34 data_bits.into_vec()
35 };
36
37 Ok(data)
38 }
39
40 pub fn read_header(&self, blob: &Blob) -> anyhow::Result<Header> {
41 let buffer = BitSlice::<u8, Msb0>::from_slice(blob.as_slice());
42
43 let buffer = &buffer[2..];
44 let (header, _) = Header::decode(buffer)?;
45
46 Ok(header)
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use bitvec::{order::Msb0, vec::BitVec};
53
54 use crate::blob::{self, Blob, Header};
55
56 #[test]
57 fn complains_if_no_blobs_are_given() {
58 let decoder = super::Decoder::default();
60
61 let err = decoder.decode(&[]).unwrap_err();
63
64 assert_eq!(err.to_string(), "No blobs to decode");
66 }
67
68 #[test]
69 fn complains_if_there_is_a_blob_from_a_different_bundle() {
70 let bundle_1_blobs = blob::Encoder::default().encode(&[100], 0).unwrap();
72 let bundle_2_blobs = blob::Encoder::default().encode(&[100], 1).unwrap();
73
74 let all_blobs = [bundle_1_blobs, bundle_2_blobs].concat();
75
76 let err = super::Decoder::default().decode(&all_blobs).unwrap_err();
78
79 assert_eq!(
81 err.to_string(),
82 "All blobs must have the same bundle id, got {0, 1}"
83 );
84 }
85
86 #[test]
87 fn complains_if_there_are_duplicate_idx() {
88 let bundle_1_blobs = blob::Encoder::default().encode(&[0; 200_000], 0).unwrap();
90 assert_eq!(bundle_1_blobs.len(), 2);
91
92 let with_duplication = [
93 bundle_1_blobs[0].clone(),
94 bundle_1_blobs[0].clone(),
95 bundle_1_blobs[1].clone(),
96 ];
97
98 let err = super::Decoder::default()
100 .decode(&with_duplication)
101 .unwrap_err();
102
103 assert_eq!(err.to_string(), "found duplicate blob idxs: 0");
105 }
106
107 #[test]
108 fn complains_if_index_missing() {
109 let blobs = blob::Encoder::default()
111 .encode(&vec![0; 400_000], 0)
112 .unwrap();
113 assert_eq!(blobs.len(), 4);
114
115 let blobs_with_holes = [blobs[0].clone(), blobs[3].clone()];
116
117 let err = super::Decoder::default()
119 .decode(&blobs_with_holes)
120 .unwrap_err();
121
122 assert_eq!(err.to_string(), "missing blobs with indexes: 1, 2");
124 }
125
126 #[test]
127 fn complains_if_no_blob_is_marked_as_last() {
128 let blobs = blob::Encoder::default()
130 .encode(&vec![0; 400_000], 0)
131 .unwrap();
132 assert_eq!(blobs.len(), 4);
133
134 let leave_out_the_last_blob = &blobs[..3];
135
136 let err = super::Decoder::default()
138 .decode(leave_out_the_last_blob)
139 .unwrap_err();
140
141 assert_eq!(err.to_string(), "no blob is marked as last");
143 }
144
145 #[test]
146 fn multiple_blobs_marked_as_being_the_last() {
147 let four_blob_bundle = blob::Encoder::default()
149 .encode(&vec![0; 400_000], 0)
150 .unwrap();
151 assert_eq!(four_blob_bundle.len(), 4);
152
153 let three_blob_bundle = blob::Encoder::default()
154 .encode(&vec![0; 300_000], 0)
155 .unwrap();
156 assert_eq!(three_blob_bundle.len(), 3);
157
158 let blobs_with_multiple_last = [
159 four_blob_bundle[0].clone(),
160 four_blob_bundle[1].clone(),
161 three_blob_bundle[2].clone(),
162 four_blob_bundle[3].clone(),
163 ];
164
165 let err = super::Decoder::default()
167 .decode(&blobs_with_multiple_last)
168 .unwrap_err();
169
170 assert_eq!(
172 err.to_string(),
173 "multiple blobs marked as being the last blob. blobs with indexes: 2, 3"
174 );
175 }
176
177 #[test]
178 fn complains_if_the_last_blob_doesnt_have_the_highest_idx() {
179 let four_blob_bundle = blob::Encoder::default()
181 .encode(&vec![0; 400_000], 0)
182 .unwrap();
183 assert_eq!(four_blob_bundle.len(), 4);
184
185 let two_blob_bundle = blob::Encoder::default()
186 .encode(&vec![0; 200_000], 0)
187 .unwrap();
188 assert_eq!(two_blob_bundle.len(), 2);
189
190 let blobs_with_last_not_highest_idx = [
191 four_blob_bundle[0].clone(),
192 four_blob_bundle[1].clone(),
193 four_blob_bundle[2].clone(),
194 two_blob_bundle[1].clone(),
195 ];
196
197 let err = super::Decoder::default()
199 .decode(&blobs_with_last_not_highest_idx)
200 .unwrap_err();
201
202 assert_eq!(
204 err.to_string(),
205 "blob with highest index is 2, but the blob marked as last has index 1"
206 );
207 }
208
209 #[test]
210 fn fails_if_num_of_bits_more_than_what_can_fit_in_a_blob() {
211 let mut blobs = blob::Encoder::default()
213 .encode(&vec![0; 100_000], 0)
214 .unwrap();
215 assert_eq!(blobs.len(), 1);
216 let blob = blobs.pop().unwrap();
217 let mut blob_data = BitVec::<u8, Msb0>::from_slice(blob.as_slice());
218
219 let corrupted_header = blob::Header::V1(blob::HeaderV1 {
220 bundle_id: 0,
221 num_bits: 256 * 4096 + 1,
222 is_last: true,
223 idx: 0,
224 });
225
226 blob_data[2..2 + Header::V1_SIZE_BITS].copy_from_bitslice(&corrupted_header.encode());
227 let corrupted_blob: Blob = blob_data.into_vec().into_boxed_slice().try_into().unwrap();
228
229 let err = super::Decoder::default()
231 .decode(&[corrupted_blob])
232 .unwrap_err();
233
234 assert_eq!(
236 err.to_string(),
237 "num_bits of blob (bundle_id: 0, idx: 0) is greater than the maximum allowed value of 1048576"
238 );
239 }
240}