tonlib_core/
cell.rs

1use std::fmt::Debug;
2use std::hash::Hash;
3use std::io;
4use std::ops::Deref;
5use std::sync::Arc;
6
7pub use bag_of_cells::*;
8use base64::Engine;
9use bitstream_io::{BigEndian, BitWrite, BitWriter};
10pub use builder::*;
11pub use error::*;
12use hmac::digest::Digest;
13use lazy_static::lazy_static;
14pub use parser::*;
15pub use raw::*;
16use sha2::Sha256;
17pub use slice::*;
18pub use ton_cell_num::*;
19pub use util::*;
20
21use crate::cell::cell_type::CellType;
22use crate::cell::level_mask::LevelMask;
23use crate::types::DEFAULT_CELL_HASH;
24use crate::TonHash;
25
26mod bag_of_cells;
27mod builder;
28mod cell_type;
29pub mod dict;
30mod error;
31mod level_mask;
32mod ton_cell_num;
33
34mod parser;
35mod raw;
36mod raw_boc_from_boc;
37mod slice;
38#[cfg(test)]
39mod test_boc;
40mod util;
41
42const DEPTH_BYTES: usize = 2;
43const MAX_LEVEL: u8 = 3;
44
45pub type ArcCell = Arc<Cell>;
46
47lazy_static! {
48    pub static ref EMPTY_CELL: Cell = Cell::default();
49    pub static ref EMPTY_ARC_CELL: ArcCell = Arc::new(Cell::default());
50}
51
52#[derive(PartialEq, Eq, Clone, Hash)]
53pub struct Cell {
54    data: Vec<u8>,
55    bit_len: usize,
56    references: Vec<ArcCell>,
57    cell_type: CellType,
58    level_mask: LevelMask,
59    hashes: [TonHash; 4],
60    depths: [u16; 4],
61}
62
63impl Cell {
64    pub fn new(
65        data: Vec<u8>,
66        bit_len: usize,
67        references: Vec<ArcCell>,
68        is_exotic: bool,
69    ) -> Result<Self, TonCellError> {
70        let cell_type = if is_exotic {
71            CellType::determine_exotic_cell_type(&data)?
72        } else {
73            CellType::Ordinary
74        };
75
76        cell_type.validate(&data, bit_len, &references)?;
77        let level_mask = cell_type.level_mask(&data, bit_len, &references)?;
78        let (hashes, depths) =
79            calculate_hashes_and_depths(cell_type, &data, bit_len, &references, level_mask)?;
80
81        let result = Self {
82            data,
83            bit_len,
84            references,
85            level_mask,
86            cell_type,
87            hashes,
88            depths,
89        };
90
91        Ok(result)
92    }
93
94    pub fn parser(&self) -> CellParser<'_> {
95        CellParser::new(self)
96    }
97
98    #[allow(clippy::let_and_return)]
99    pub fn parse<F, T>(&self, parse: F) -> Result<T, TonCellError>
100    where
101        F: FnOnce(&mut CellParser) -> Result<T, TonCellError>,
102    {
103        let mut parser = self.parser();
104        let res = parse(&mut parser);
105        res
106    }
107
108    pub fn parse_fully<F, T>(&self, parse: F) -> Result<T, TonCellError>
109    where
110        F: FnOnce(&mut CellParser) -> Result<T, TonCellError>,
111    {
112        let mut reader = self.parser();
113        let res = parse(&mut reader);
114        reader.ensure_empty()?;
115        res
116    }
117
118    pub fn reference(&self, idx: usize) -> Result<&ArcCell, TonCellError> {
119        self.references.get(idx).ok_or(TonCellError::InvalidIndex {
120            idx,
121            ref_count: self.references.len(),
122        })
123    }
124
125    pub fn data(&self) -> &[u8] {
126        self.data.as_slice()
127    }
128
129    pub fn bit_len(&self) -> usize {
130        self.bit_len
131    }
132
133    pub fn references(&self) -> &[ArcCell] {
134        self.references.as_slice()
135    }
136
137    pub(crate) fn get_level_mask(&self) -> u32 {
138        self.level_mask.mask()
139    }
140
141    pub fn cell_depth(&self) -> u16 {
142        self.get_depth(MAX_LEVEL)
143    }
144
145    pub fn get_depth(&self, level: u8) -> u16 {
146        self.depths[level.min(3) as usize]
147    }
148
149    pub fn cell_hash(&self) -> TonHash {
150        self.get_hash(MAX_LEVEL)
151    }
152
153    pub fn get_hash(&self, level: u8) -> TonHash {
154        self.hashes[level.min(3) as usize].clone()
155    }
156
157    pub fn is_exotic(&self) -> bool {
158        self.cell_type != CellType::Ordinary
159    }
160
161    pub fn is_library(&self) -> bool {
162        self.cell_type == CellType::Library
163    }
164
165    pub fn cell_hash_base64(&self) -> String {
166        self.cell_hash().to_base64()
167    }
168
169    pub fn load_snake_formatted_string(&self) -> Result<String, TonCellError> {
170        let mut cell: &Cell = self;
171        let mut first_cell = true;
172        let mut uri = String::new();
173        loop {
174            let parsed_cell = if first_cell {
175                String::from_utf8_lossy(&cell.data[1..]).to_string()
176            } else {
177                String::from_utf8_lossy(&cell.data).to_string()
178            };
179            uri.push_str(&parsed_cell);
180            match cell.references.len() {
181                0 => return Ok(uri),
182                1 => {
183                    cell = cell.references[0].deref();
184                    first_cell = false;
185                }
186                n => {
187                    return Err(TonCellError::boc_deserialization_error(format!(
188                        "Invalid snake format string: found cell with {} references",
189                        n
190                    )))
191                }
192            }
193        }
194    }
195
196    fn parse_snake_data(&self, buffer: &mut Vec<u8>) -> Result<(), TonCellError> {
197        let mut cell = self;
198        let mut first_cell = true;
199        loop {
200            let mut parser = cell.parser();
201            if first_cell {
202                let first_byte = parser.load_u8(8)?;
203
204                if first_byte != 0 {
205                    return Err(TonCellError::boc_deserialization_error(
206                        "Invalid snake format",
207                    ));
208                }
209            }
210            let remaining_bytes = parser.remaining_bytes();
211            let mut data = parser.load_bytes(remaining_bytes)?;
212            buffer.append(&mut data);
213            match cell.references.len() {
214                0 => return Ok(()),
215                1 => {
216                    cell = cell.references[0].deref();
217                    first_cell = false;
218                }
219                n => {
220                    return Err(TonCellError::boc_deserialization_error(format!(
221                        "Invalid snake format string: found cell with {} references",
222                        n
223                    )))
224                }
225            }
226        }
227    }
228
229    pub fn to_arc(self) -> ArcCell {
230        Arc::new(self)
231    }
232
233    /// It is recommended to use CellParser::next_reference() instead
234    #[deprecated]
235    pub fn expect_reference_count(&self, expected_refs: usize) -> Result<(), TonCellError> {
236        let ref_count = self.references.len();
237        if ref_count != expected_refs {
238            Err(TonCellError::CellParserError(format!(
239                "Cell should contain {} reference cells, actual: {}",
240                expected_refs, ref_count
241            )))
242        } else {
243            Ok(())
244        }
245    }
246}
247
248impl Debug for Cell {
249    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250        write_cell_debug(f, self, 0)
251    }
252}
253
254impl Default for Cell {
255    fn default() -> Self {
256        Self {
257            data: Default::default(),
258            bit_len: Default::default(),
259            references: Default::default(),
260            cell_type: Default::default(),
261            level_mask: Default::default(),
262            hashes: [DEFAULT_CELL_HASH; 4],
263            depths: Default::default(),
264        }
265    }
266}
267
268fn get_repr_for_data(
269    original_data_bit_len: usize,
270    (data, data_bit_len): (&[u8], usize),
271    refs: &[ArcCell],
272    level_mask: LevelMask,
273    level: u8,
274    cell_type: CellType,
275) -> Result<Vec<u8>, TonCellError> {
276    // Allocate
277    let data_len = data.len();
278    // descriptors + data + (hash + depth) * refs_count
279    let buffer_len = 2 + data_len + (32 + 2) * refs.len();
280
281    let mut writer = BitWriter::endian(Vec::with_capacity(buffer_len), BigEndian);
282    let d1 = get_refs_descriptor(cell_type, refs, level_mask.apply(level).mask())?;
283    let d2 = get_bits_descriptor(original_data_bit_len)?;
284
285    // Write descriptors
286    writer.write_var(8, d1).map_cell_parser_error()?;
287    writer.write_var(8, d2).map_cell_parser_error()?;
288    // Write main data
289    write_data(&mut writer, data, data_bit_len).map_cell_parser_error()?;
290    // Write ref data
291    write_ref_depths(&mut writer, refs, cell_type, level)?;
292    write_ref_hashes(&mut writer, refs, cell_type, level)?;
293
294    let result = writer
295        .writer()
296        .ok_or_else(|| TonCellError::cell_builder_error("Stream for cell repr is not byte-aligned"))
297        .map(|b| b.to_vec());
298
299    result
300}
301
302/// This function replicates unknown logic of resolving cell data
303/// https://github.com/ton-blockchain/ton/blob/24dc184a2ea67f9c47042b4104bbb4d82289fac1/crypto/vm/cells/DataCell.cpp#L214
304fn calculate_hashes_and_depths(
305    cell_type: CellType,
306    data: &[u8],
307    bit_len: usize,
308    references: &[ArcCell],
309    level_mask: LevelMask,
310) -> Result<([TonHash; 4], [u16; 4]), TonCellError> {
311    let hash_count = if cell_type == CellType::PrunedBranch {
312        1
313    } else {
314        level_mask.hash_count()
315    };
316
317    let total_hash_count = level_mask.hash_count();
318    let hash_i_offset = total_hash_count - hash_count;
319
320    let mut depths: Vec<u16> = Vec::with_capacity(hash_count);
321    let mut hashes: Vec<TonHash> = Vec::with_capacity(hash_count);
322
323    // Iterate through significant levels
324    for (hash_i, level_i) in (0..=level_mask.level())
325        .filter(|&i| level_mask.is_significant(i))
326        .enumerate()
327    {
328        if hash_i < hash_i_offset {
329            continue;
330        }
331
332        let (current_data, current_bit_len) = if hash_i == hash_i_offset {
333            (data, bit_len)
334        } else {
335            let previous_hash = hashes
336                .get(hash_i - hash_i_offset - 1)
337                .ok_or_else(|| TonCellError::InternalError("Can't get right hash".to_owned()))?;
338            (previous_hash.as_slice(), 256)
339        };
340
341        // Calculate Depth
342        let depth = if references.is_empty() {
343            0
344        } else {
345            let max_ref_depth = references.iter().fold(0, |max_depth, reference| {
346                let child_depth = cell_type.child_depth(reference, level_i);
347                max_depth.max(child_depth)
348            });
349
350            max_ref_depth + 1
351        };
352
353        // Calculate Hash
354        let repr = get_repr_for_data(
355            bit_len,
356            (current_data, current_bit_len),
357            references,
358            level_mask,
359            level_i,
360            cell_type,
361        )?;
362        let hash = Sha256::new_with_prefix(repr).finalize()[..]
363            .try_into()
364            .map_err(|error| {
365                TonCellError::InternalError(format!(
366                    "Can't get [u8; 32] from finalized hash with error: {error}"
367                ))
368            })?;
369
370        depths.push(depth);
371        hashes.push(hash);
372    }
373
374    cell_type.resolve_hashes_and_depths(hashes, depths, data, bit_len, level_mask)
375}
376
377/// Calculates d1 descriptor for cell
378/// See https://docs.ton.org/tvm.pdf 3.1.4 for details
379fn get_refs_descriptor(
380    cell_type: CellType,
381    references: &[ArcCell],
382    level_mask: u32,
383) -> Result<u8, TonCellError> {
384    if references.len() > MAX_CELL_REFERENCES {
385        Err(TonCellError::InvalidCellData(
386            "Cell should not contain more than 4 references".to_string(),
387        ))
388    } else if level_mask > MAX_LEVEL_MASK {
389        Err(TonCellError::InvalidCellData(
390            "Cell level mask can not be higher than 3".to_string(),
391        ))
392    } else {
393        let cell_type_var = (cell_type != CellType::Ordinary) as u8;
394        let d1 = references.len() as u8 + 8 * cell_type_var + level_mask as u8 * 32;
395        Ok(d1)
396    }
397}
398
399/// Calculates d2 descriptor for cell
400/// See https://docs.ton.org/tvm.pdf 3.1.4 for details
401fn get_bits_descriptor(bit_len: usize) -> Result<u8, TonCellError> {
402    if bit_len > MAX_CELL_BITS {
403        Err(TonCellError::InvalidCellData(
404            "Cell data length should not contain more than 1023 bits".to_string(),
405        ))
406    } else {
407        let d2 = (bit_len / 8 + bit_len.div_ceil(8)) as u8;
408        Ok(d2)
409    }
410}
411
412fn write_data(
413    writer: &mut BitWriter<Vec<u8>, BigEndian>,
414    data: &[u8],
415    bit_len: usize,
416) -> Result<(), io::Error> {
417    let data_len = data.len();
418    let rest_bits = bit_len % 8;
419    let full_bytes = rest_bits == 0;
420
421    if !full_bytes {
422        writer.write_bytes(&data[..data_len - 1])?;
423        let last_byte = data[data_len - 1];
424        let l = last_byte | (1 << (8 - rest_bits - 1));
425        writer.write_var(8, l)?;
426    } else {
427        writer.write_bytes(data)?;
428    }
429
430    Ok(())
431}
432
433fn write_ref_depths(
434    writer: &mut BitWriter<Vec<u8>, BigEndian>,
435    refs: &[ArcCell],
436    parent_cell_type: CellType,
437    level: u8,
438) -> Result<(), TonCellError> {
439    for reference in refs {
440        let child_depth = if matches!(
441            parent_cell_type,
442            CellType::MerkleProof | CellType::MerkleUpdate
443        ) {
444            reference.get_depth(level + 1)
445        } else {
446            reference.get_depth(level)
447        };
448
449        writer
450            .write_var(8, child_depth / 256)
451            .map_cell_parser_error()?;
452        writer
453            .write_var(8, child_depth % 256)
454            .map_cell_parser_error()?;
455    }
456
457    Ok(())
458}
459
460fn write_ref_hashes(
461    writer: &mut BitWriter<Vec<u8>, BigEndian>,
462    refs: &[ArcCell],
463    parent_cell_type: CellType,
464    level: u8,
465) -> Result<(), TonCellError> {
466    for reference in refs {
467        let child_hash = if matches!(
468            parent_cell_type,
469            CellType::MerkleProof | CellType::MerkleUpdate
470        ) {
471            reference.get_hash(level + 1)
472        } else {
473            reference.get_hash(level)
474        };
475
476        writer
477            .write_bytes(child_hash.as_slice())
478            .map_cell_parser_error()?;
479    }
480
481    Ok(())
482}
483
484fn write_cell_debug(
485    f: &mut std::fmt::Formatter<'_>,
486    cell: &Cell,
487    indent_level: usize,
488) -> std::fmt::Result {
489    let indent = "    ".repeat(indent_level);
490    // Generate the data display string
491    let mut data_display: String = cell.data.iter().fold(String::new(), |mut acc, &byte| {
492        acc.push_str(&format!("{:02X}", byte));
493        acc
494    });
495
496    let data_display = if data_display.is_empty() {
497        "_"
498    } else {
499        // Our completion tag ONLY shows that the last byte is incomplete
500        // It does not correspond to real completion tag defined in
501        // p1.0.2 of https://docs.ton.org/tvm.pdf for details
502        // Null termination of bit-string defined in that document is omitted for clarity
503        if !cell.bit_len.is_multiple_of(8) {
504            data_display.push('_');
505        }
506        &data_display
507    };
508
509    if cell.references.is_empty() {
510        // Compact format for cells without references
511        writeln!(
512            f,
513            "{}Cell x{{Type: {:?}, data: [{}], bit_len: {}}}",
514            indent, cell.cell_type, data_display, cell.bit_len
515        )
516    } else {
517        // Full format for cells with references
518        writeln!(
519            f,
520            "{}Cell x{{Type: {:?}, data: [{}], bit_len: {}, references: [",
521            indent, cell.cell_type, data_display, cell.bit_len
522        )?;
523        for reference in &cell.references {
524            write_cell_debug(f, reference, indent_level + 1)?;
525        }
526        writeln!(f, "{}]}}", indent)
527    }
528}
529
530#[cfg(test)]
531mod test {
532    use std::sync::Arc;
533
534    use super::cell_type::CellType;
535    use super::{get_bits_descriptor, get_refs_descriptor, Cell};
536    use crate::cell::CellBuilder;
537
538    #[test]
539    fn default_cell() {
540        let result = Cell::default();
541
542        let expected = Cell::new(vec![], 0, vec![], false).unwrap();
543
544        assert_eq!(result, expected)
545    }
546
547    #[test]
548    fn d1_descriptor_test() {
549        let empty_cell = Arc::new(CellBuilder::new().build().unwrap());
550
551        let r1 = get_refs_descriptor(CellType::Ordinary, &[], 0).unwrap();
552        assert_eq!(r1, 0);
553
554        let r2 = get_refs_descriptor(CellType::Ordinary, &[], 4).is_err();
555        assert!(r2);
556
557        let r3 = get_refs_descriptor(CellType::Ordinary, &[empty_cell.clone()], 3).unwrap();
558        assert_eq!(r3, 97);
559
560        let r4 =
561            get_refs_descriptor(CellType::Ordinary, vec![empty_cell; 5].as_slice(), 3).is_err();
562        assert!(r4);
563    }
564
565    #[test]
566    fn d2_descriptor_test() {
567        let r1 = get_bits_descriptor(0).unwrap();
568        assert_eq!(r1, 0);
569
570        let r2 = get_bits_descriptor(1023).unwrap();
571        assert_eq!(r2, 255);
572
573        let r3 = get_bits_descriptor(1024).is_err();
574        assert!(r3)
575    }
576}