tonlib_core/cell/
raw.rs

1use std::io::Cursor;
2
3use bitstream_io::{BigEndian, BitWrite, BitWriter, ByteRead, ByteReader};
4use crc::Crc;
5use lazy_static::lazy_static;
6
7use crate::cell::level_mask::LevelMask;
8use crate::cell::{MapTonCellError, TonCellError};
9
10lazy_static! {
11    pub static ref CRC_32_ISCSI: Crc<u32> = Crc::<u32>::new(&crc::CRC_32_ISCSI);
12}
13
14/// Raw representation of Cell.
15///
16/// References are stored as indices in BagOfCells.
17#[derive(PartialEq, Eq, Debug, Clone, Hash)]
18pub(crate) struct RawCell {
19    pub(crate) data: Vec<u8>,
20    pub(crate) bit_len: usize,
21    pub(crate) references: Vec<usize>,
22    pub(crate) is_exotic: bool,
23    level_mask: u32,
24}
25
26impl RawCell {
27    pub(crate) fn new(
28        data: Vec<u8>,
29        bit_len: usize,
30        references: Vec<usize>,
31        level_mask: u32,
32        is_exotic: bool,
33    ) -> Self {
34        Self {
35            data,
36            bit_len,
37            references,
38            level_mask: level_mask & 7,
39            is_exotic,
40        }
41    }
42}
43
44/// Raw representation of BagOfCells.
45///
46/// `cells` must be topologically sorted.
47#[derive(PartialEq, Eq, Debug, Clone, Hash)]
48pub(crate) struct RawBagOfCells {
49    pub(crate) cells: Vec<RawCell>,
50    pub(crate) roots: Vec<usize>,
51}
52
53const GENERIC_BOC_MAGIC: u32 = 0xb5ee9c72;
54const _INDEXED_BOC_MAGIC: u32 = 0x68ff65f3;
55const _INDEXED_CRC32_MAGIC: u32 = 0xacc3a728;
56
57impl RawBagOfCells {
58    pub(crate) fn parse(serial: &[u8]) -> Result<RawBagOfCells, TonCellError> {
59        let cursor = Cursor::new(serial);
60
61        let mut reader: ByteReader<Cursor<&[u8]>, BigEndian> =
62            ByteReader::endian(cursor, BigEndian);
63        // serialized_boc#b5ee9c72
64        let magic = reader.read::<u32>().map_boc_deserialization_error()?;
65
66        let (has_idx, has_crc32c, _has_cache_bits, size) = match magic {
67            GENERIC_BOC_MAGIC => {
68                // has_idx:(## 1) has_crc32c:(## 1) has_cache_bits:(## 1) flags:(## 2) { flags = 0 }
69                let header = reader.read::<u8>().map_boc_deserialization_error()?;
70                let has_idx = header & 0b1000_0000 != 0;
71                let has_crc32c = header & 0b0100_0000 != 0;
72                let has_cache_bits = header & 0b0010_0000 != 0;
73
74                // size:(## 3) { size <= 4 }
75                let size = header & 0b0000_0111;
76                if size > 4 {
77                    return Err(TonCellError::boc_deserialization_error(format!(
78                        "Invalid size {size}. Size should be <= 4."
79                    )));
80                }
81
82                (has_idx, has_crc32c, has_cache_bits, size)
83            }
84            magic => {
85                return Err(TonCellError::boc_deserialization_error(format!(
86                    "Unsupported cell magic number: {:#}",
87                    magic
88                )));
89            }
90        };
91        //   off_bytes:(## 8) { off_bytes <= 8 }
92        let off_bytes = reader.read::<u8>().map_boc_deserialization_error()?;
93        //cells:(##(size * 8))
94        let cells = read_var_size(&mut reader, size)?;
95        //   roots:(##(size * 8)) { roots >= 1 }
96        let roots = read_var_size(&mut reader, size)?;
97        //   absent:(##(size * 8)) { roots + absent <= cells }
98        let _absent = read_var_size(&mut reader, size)?;
99        //   tot_cells_size:(##(off_bytes * 8))
100        let _tot_cells_size = read_var_size(&mut reader, off_bytes)?;
101        //   root_list:(roots * ##(size * 8))
102        let mut root_list = vec![];
103        for _ in 0..roots {
104            root_list.push(read_var_size(&mut reader, size)?)
105        }
106        //   index:has_idx?(cells * ##(off_bytes * 8))
107        let mut index = vec![];
108        if has_idx {
109            for _ in 0..cells {
110                index.push(read_var_size(&mut reader, off_bytes)?)
111            }
112        }
113        //   cell_data:(tot_cells_size * [ uint8 ])
114        let mut cell_vec = Vec::with_capacity(cells);
115
116        for _ in 0..cells {
117            let cell = read_cell(&mut reader, size)?;
118            cell_vec.push(cell);
119        }
120        //   crc32c:has_crc32c?uint32
121        let _crc32c = if has_crc32c {
122            reader.read::<u32>().map_boc_deserialization_error()?
123        } else {
124            0
125        };
126        // TODO: Check crc32
127
128        Ok(RawBagOfCells {
129            cells: cell_vec,
130            roots: root_list,
131        })
132    }
133
134    pub(crate) fn serialize(&self, has_crc32: bool) -> Result<Vec<u8>, TonCellError> {
135        //Based on https://github.com/toncenter/tonweb/blob/c2d5d0fc23d2aec55a0412940ce6e580344a288c/src/boc/Cell.js#L198
136
137        let root_count = self.roots.len();
138        let num_ref_bits = 32 - (self.cells.len() as u32).leading_zeros();
139        let num_ref_bytes = num_ref_bits.div_ceil(8);
140        let has_idx = false;
141
142        let mut full_size = 0u32;
143
144        for cell in &self.cells {
145            full_size += raw_cell_size(cell, num_ref_bytes);
146        }
147
148        let num_offset_bits = 32 - full_size.leading_zeros();
149        let num_offset_bytes = num_offset_bits.div_ceil(8);
150
151        let total_size = 4 + // magic
152            1 + // flags and s_bytes
153            1 + // offset_bytes
154            3 * num_ref_bytes + // cells_num, roots, complete
155            num_offset_bytes + // full_size
156            num_ref_bytes + // root_idx
157            (if has_idx { self.cells.len() as u32 * num_offset_bytes } else { 0 }) +
158            full_size +
159            (if has_crc32 { 4 } else { 0 });
160
161        let mut writer = BitWriter::endian(Vec::with_capacity(total_size as usize), BigEndian);
162
163        writer
164            .write_var(32, GENERIC_BOC_MAGIC)
165            .map_boc_serialization_error()?;
166
167        //write flags byte
168        let has_cache_bits = false;
169        let flags: u8 = 0;
170        writer.write_bit(has_idx).map_boc_serialization_error()?;
171        writer.write_bit(has_crc32).map_boc_serialization_error()?;
172        writer
173            .write_bit(has_cache_bits)
174            .map_boc_serialization_error()?;
175        writer.write_var(2, flags).map_boc_serialization_error()?;
176        writer
177            .write_var(3, num_ref_bytes)
178            .map_boc_serialization_error()?;
179        writer
180            .write_var(8, num_offset_bytes)
181            .map_boc_serialization_error()?;
182        writer
183            .write_var(8 * num_ref_bytes, self.cells.len() as u32)
184            .map_boc_serialization_error()?;
185        writer
186            .write_var(8 * num_ref_bytes, root_count as u32)
187            .map_boc_serialization_error()?;
188        writer
189            .write_var(8 * num_ref_bytes, 0)
190            .map_boc_serialization_error()?; // Complete BOCs only
191        writer
192            .write_var(8 * num_offset_bytes, full_size)
193            .map_boc_serialization_error()?;
194        for &root in &self.roots {
195            writer
196                .write_var(8 * num_ref_bytes, root as u32)
197                .map_boc_serialization_error()?;
198        }
199
200        for cell in &self.cells {
201            write_raw_cell(&mut writer, cell, num_ref_bytes)?;
202        }
203
204        if has_crc32 {
205            let bytes = writer.writer().ok_or_else(|| {
206                TonCellError::boc_serialization_error("Stream is not byte-aligned")
207            })?;
208            let cs = CRC_32_ISCSI.checksum(bytes.as_slice());
209            writer
210                .write_bytes(cs.to_le_bytes().as_slice())
211                .map_boc_serialization_error()?;
212        }
213        writer.byte_align().map_boc_serialization_error()?;
214        let res = writer
215            .writer()
216            .ok_or_else(|| TonCellError::boc_serialization_error("Stream is not byte-aligned"))?;
217        Ok(res.clone())
218    }
219}
220
221fn read_cell(
222    reader: &mut ByteReader<Cursor<&[u8]>, BigEndian>,
223    size: u8,
224) -> Result<RawCell, TonCellError> {
225    let d1 = reader.read::<u8>().map_boc_deserialization_error()?;
226    let d2 = reader.read::<u8>().map_boc_deserialization_error()?;
227
228    let ref_num = d1 & 0b111;
229    let is_exotic = (d1 & 0b1000) != 0;
230    let has_hashes = (d1 & 0b10000) != 0;
231    let level_mask = (d1 >> 5) as u32;
232    let data_size = ((d2 >> 1) + (d2 & 1)).into();
233    let full_bytes = (d2 & 0x01) == 0;
234
235    if has_hashes {
236        let hash_count = LevelMask::new(level_mask).hash_count();
237        let skip_size = hash_count * (32 + 2);
238
239        // TODO: check depth and hashes
240        reader
241            .skip(skip_size as u32)
242            .map_boc_deserialization_error()?;
243    }
244
245    let mut data = reader
246        .read_to_vec(data_size)
247        .map_boc_deserialization_error()?;
248
249    let data_len = data.len();
250    let padding_len = if data_len > 0 && !full_bytes {
251        // Fix last byte,
252        // see https://github.com/toncenter/tonweb/blob/c2d5d0fc23d2aec55a0412940ce6e580344a288c/src/boc/BitString.js#L302
253        let num_zeros = data[data_len - 1].trailing_zeros();
254        if num_zeros >= 8 {
255            return Err(TonCellError::boc_deserialization_error(
256                "Last byte of binary must not be zero if full_byte flag is not set",
257            ));
258        }
259        data[data_len - 1] &= !(1 << num_zeros);
260        num_zeros + 1
261    } else {
262        0
263    };
264    let bit_len = data.len() * 8 - padding_len as usize;
265    let mut references: Vec<usize> = Vec::new();
266    for _ in 0..ref_num {
267        references.push(read_var_size(reader, size)?);
268    }
269    let cell = RawCell::new(data, bit_len, references, level_mask, is_exotic);
270    Ok(cell)
271}
272
273fn raw_cell_size(cell: &RawCell, ref_size_bytes: u32) -> u32 {
274    let data_len = cell.bit_len.div_ceil(8);
275    2 + data_len as u32 + cell.references.len() as u32 * ref_size_bytes
276}
277
278fn write_raw_cell(
279    writer: &mut BitWriter<Vec<u8>, BigEndian>,
280    cell: &RawCell,
281    ref_size_bytes: u32,
282) -> Result<(), TonCellError> {
283    let level = cell.level_mask;
284    let is_exotic = cell.is_exotic as u32;
285    let num_refs = cell.references.len() as u32;
286    let d1 = num_refs + is_exotic * 8 + level * 32;
287
288    let padding_bits = cell.bit_len % 8;
289    let full_bytes = padding_bits == 0;
290    let data = cell.data.as_slice();
291    let data_len_bytes = cell.bit_len.div_ceil(8);
292    // data_len_bytes <= 128 by spec, but d2 must be u8 by spec as well
293    let d2 = (data_len_bytes * 2 - if full_bytes { 0 } else { 1 }) as u8; //subtract 1 if the last byte is not full
294
295    writer.write_var(8, d1).map_boc_serialization_error()?;
296    writer.write_var(8, d2).map_boc_serialization_error()?;
297    if !full_bytes {
298        writer
299            .write_bytes(&data[..data_len_bytes - 1])
300            .map_boc_serialization_error()?;
301        let last_byte = data[data_len_bytes - 1];
302        let l = last_byte | (1 << (8 - padding_bits - 1));
303        writer.write_var(8, l).map_boc_serialization_error()?;
304    } else {
305        writer.write_bytes(data).map_boc_serialization_error()?;
306    }
307
308    for r in cell.references.as_slice() {
309        writer
310            .write_var(8 * ref_size_bytes, *r as u32)
311            .map_boc_serialization_error()?;
312    }
313
314    Ok(())
315}
316
317fn read_var_size(
318    reader: &mut ByteReader<Cursor<&[u8]>, BigEndian>,
319    n: u8,
320) -> Result<usize, TonCellError> {
321    let bytes = reader
322        .read_to_vec(n.into())
323        .map_boc_deserialization_error()?;
324
325    let mut result = 0;
326    for &byte in &bytes {
327        result <<= 8;
328        result |= usize::from(byte);
329    }
330    Ok(result)
331}
332
333#[cfg(test)]
334mod tests {
335    use super::*;
336
337    #[test]
338    fn test_raw_cell_serialize() {
339        let raw_cell = RawCell::new(vec![1; 128], 1023, vec![], 255, false);
340        let raw_bag = RawBagOfCells {
341            cells: vec![raw_cell],
342            roots: vec![0],
343        };
344        assert!(raw_bag.serialize(false).is_ok());
345    }
346}