fuel_block_committer_encoding/bundle/
decoder.rs1use std::{io::Read, marker::PhantomData};
2
3use anyhow::Context;
4use flate2::read::GzDecoder;
5
6use crate::bundle::BundleV1;
7
8#[derive(Clone, Debug, Default)]
9pub struct Decoder {
10 private: PhantomData<()>,
11}
12
13impl Decoder {
14 pub fn decode(&self, data: &[u8]) -> anyhow::Result<super::Bundle> {
15 if data.len() < 2 {
16 anyhow::bail!("Bundle data too short to contain version");
17 }
18 let version = u16::from_be_bytes([data[0], data[1]]);
19 if version != 1 {
20 anyhow::bail!("Unsupported bundle version: {version}");
21 }
22
23 let data = Self::decompress(&data[2..])
24 .with_context(|| "failed to decompress BundleV1 contents")?;
25
26 let blocks: BundleV1 = postcard::from_bytes(&data)
27 .with_context(|| "failed to postcard decode decompressed contents of BundleV1")?;
28
29 Ok(super::Bundle::V1(blocks))
30 }
31
32 fn decompress(data: &[u8]) -> anyhow::Result<Vec<u8>> {
33 let mut decoder = GzDecoder::new(data);
34
35 let mut buf = vec![];
36 decoder.read_to_end(&mut buf)?;
37
38 Ok(buf)
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use crate::bundle::{Bundle, BundleV1, Encoder};
45
46 #[test]
47 fn complains_about_unsupported_version() {
48 let encoder = Encoder::default();
50 let mut encoded_bundle = encoder
51 .encode(Bundle::V1(BundleV1 { blocks: vec![] }))
52 .unwrap();
53 encoded_bundle[..2].copy_from_slice(&5u16.to_be_bytes());
54 let decoder = super::Decoder::default();
55
56 let err = decoder.decode(&encoded_bundle).unwrap_err();
58
59 let expected = "Unsupported bundle version: 5";
61 assert_eq!(err.to_string(), expected);
62 }
63
64 #[test]
65 fn complains_about_not_enough_data() {
66 let decoder = super::Decoder::default();
68
69 let err = decoder.decode(&[1]).unwrap_err();
71
72 assert_eq!(err.to_string(), "Bundle data too short to contain version");
74 }
75}