fuel_block_committer_encoding/blob/
decoder.rs

1use 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        // given
59        let decoder = super::Decoder::default();
60
61        // when
62        let err = decoder.decode(&[]).unwrap_err();
63
64        // then
65        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        // given
71        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        // when
77        let err = super::Decoder::default().decode(&all_blobs).unwrap_err();
78
79        // then
80        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        // given
89        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        // when
99        let err = super::Decoder::default()
100            .decode(&with_duplication)
101            .unwrap_err();
102
103        // then
104        assert_eq!(err.to_string(), "found duplicate blob idxs: 0");
105    }
106
107    #[test]
108    fn complains_if_index_missing() {
109        // given
110        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        // when
118        let err = super::Decoder::default()
119            .decode(&blobs_with_holes)
120            .unwrap_err();
121
122        // then
123        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        // given
129        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        // when
137        let err = super::Decoder::default()
138            .decode(leave_out_the_last_blob)
139            .unwrap_err();
140
141        // then
142        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        // given
148        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        // when
166        let err = super::Decoder::default()
167            .decode(&blobs_with_multiple_last)
168            .unwrap_err();
169
170        // then
171        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        // given
180        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        // when
198        let err = super::Decoder::default()
199            .decode(&blobs_with_last_not_highest_idx)
200            .unwrap_err();
201
202        // then
203        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        // given
212        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        // when
230        let err = super::Decoder::default()
231            .decode(&[corrupted_blob])
232            .unwrap_err();
233
234        // then
235        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}