Skip to main content

tycho_types/
lib.rs

1#![warn(missing_docs)]
2#![allow(clippy::question_mark)]
3
4//! Tycho types.
5//!
6//! This crate is a collection of basic structures and models for the
7//! Tycho node. The [`Cell`] represents the core
8//! data structure which is used as an atom for building other structures.
9//!
10//! *Compiler support: [requires `rustc` 1.65+][msrv]*
11//!
12//! [msrv]: #supported-rust-versions
13//!
14//! ## `Cell` vs `CellSlice` vs `CellBuilder`
15//!
16//! - [`Cell`] is an immutable tree and provides only basic methods for accessing
17//!   nodes and some meta info.
18//!
19//! - [`CellSlice`] is a read-only view for a part of some cell. It can only
20//!   be obtained from an existing cell. A cell contains **up to 1023 bits** and
21//!   **up to 4 references**. Minimal data unit is bit, so a cell slice is similar
22//!   to a couple of ranges (bit range and refs range).
23//!
24//! - [`CellBuilder`] is used to create a new cell. It is used as an append-only
25//!   data structure and is the only way to create a new cell with the provided data.
26//!   Cell creation depends on a context (e.g. message creation in a wallet or a
27//!   TVM execution with gas tracking), so [`CellBuilder::build_ext`] accepts
28//!   a [`CellContext`] parameter which can be used to track and modify cells creation.
29//!
30//! ## BOC
31//!
32//! BOC (Bag Of Cells) is a format for representing a tree of cells as bytes.
33//! [`Boc`] type is used to convert between bytes and **cells** of the same family.
34//! [`BocRepr`] helper can be used to convert between bytes and **models** (which
35//! are representable as cells).
36//!
37//! ### Merkle stuff
38//!
39//! - Pruned branch is a "building block" of merkle structures. A single pruned branch
40//!   cell replaces a whole subtree and contains just the hash of its root cell hash.
41//!
42//! - [`MerkleProof`] contains a subset of original tree of cells. In most cases
43//!   it is created from [`UsageTree`] of some visited cells. Merkle proof is used
44//!   to proof that something was presented in the origin tree and provide some additional
45//!   context.
46//!
47//! - [`MerkleUpdate`] describes a difference between two trees of cells. It can be
48//!   applied to old cell to create a new cell.
49//!
50//! ### Numeric stuff
51//!
52//! This crate introduces some unusual number types with custom bit size or variable
53//! encoding. They are only used in models, but may be useful in user code.
54//!
55//! ### Dictionaries
56//!
57//! Dictionary, erroneously called HashmapE in the original TLB schema, is an
58//! important building block of blockchain models. It is similar to `BTreeMap`.
59//! Dictionary is an immutable structure over tree of cells with fixed-length
60//! keys and arbitrary values. Updates create a new cell tree each time, so
61//! it's quite an expensive data structure to work with.
62//!
63//! ### Models
64//!
65//! There is a simple definition of nearly all blockchain models. This definition
66//! doesn't contain any complex logic, but could be extended via extension traits.
67//! The names and structure of the models are slightly different from the
68//! definition in the TLB for the sake of consistency of use.
69//!
70//! All models implement [`Load`] and [`Store`] traits for conversion from/to cells.
71//!
72//! - [`RawDict`] constrains only key size in bits. It is useful when a dictionary
73//!   can contain multiple types of values.
74//!
75//! - [`Dict`] is a strongly typed version of definition and is a preferable way
76//!   of working with this data structure. Key type must implement [`DictKey`] trait,
77//!   which is implemented for numbers and addresses.
78//!
79//! - [`AugDict`] adds additional values for all nodes. You can use it to quickly
80//!   access a subtotal of values for each subtree.
81//!   NOTE: this type is partially implemented due to its complexity.
82//!
83//! ## Supported Rust Versions
84//!
85//! This crate is built against the latest stable release. The minimum supported
86//! version is 1.65. The current crate version is not guaranteed to build on
87//! Rust versions earlier than the minimum supported version.
88//!
89//! [`Cell`]: cell::Cell
90//! [`Rc`]: std::rc::Rc
91//! [`Arc`]: std::sync::Arc
92//! [`RcCell`]: prelude::RcCell
93//! [`ArcCell`]: prelude::ArcCell
94//! [`CellSlice`]: cell::CellSlice
95//! [`CellBuilder`]: cell::CellBuilder
96//! [`Cell::as_slice`]: cell::CellImpl::as_slice
97//! [`CellBuilder::build_ext`]: cell::CellBuilder::build_ext
98//! [`CellContext`]: cell::CellContext
99//! [`Boc`]: boc::Boc
100//! [`BocRepr`]: boc::BocRepr
101//! [`UsageTree`]: cell::UsageTree
102//! [`MerkleProof`]: merkle::MerkleProof
103//! [`MerkleUpdate`]: merkle::MerkleUpdate
104//! [`RawDict`]: dict::RawDict
105//! [`Dict`]: dict::Dict
106//! [`DictKey`]: dict::DictKey
107//! [`AugDict`]: dict::AugDict
108//! [`Load`]: cell::Load
109//! [`Store`]: cell::Store
110/// Prevents using `From::from` for plain error conversion.
111macro_rules! ok {
112    ($e:expr $(,)?) => {
113        match $e {
114            core::result::Result::Ok(val) => val,
115            core::result::Result::Err(err) => return core::result::Result::Err(err),
116        }
117    };
118}
119
120#[allow(unused)]
121macro_rules! assert_impl_all {
122    ($type:ty: $($trait:path),+ $(,)?) => {
123        const _: fn() = || {
124            // Only callable when `$type` implements all traits in `$($trait)+`.
125            fn assert_impl_all<T: ?Sized $(+ $trait)+>() {}
126            assert_impl_all::<$type>();
127        };
128    };
129}
130
131extern crate self as tycho_types;
132
133pub mod boc;
134pub mod cell;
135pub mod crc;
136pub mod dict;
137pub mod merkle;
138pub mod num;
139pub mod prelude;
140pub mod util;
141
142#[cfg(feature = "models")]
143pub mod models;
144
145#[cfg(feature = "abi")]
146pub mod abi;
147
148#[cfg(feature = "arbitrary")]
149pub mod arbitrary;
150
151pub mod error;
152#[cfg(test)]
153mod tests {
154    use crate::cell::{CellTreeStats, MAX_BIT_LEN};
155    use crate::prelude::*;
156    use crate::util::decode_base64;
157
158    #[test]
159    fn correct_deserialization() {
160        let data = decode_base64("te6ccgEBBAEAzwACg4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAIBAEAAAAAAAAAAAAAAAAAAAAAAAAAAm2c6ClpzoTVSAHvzVQGDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHKq1w7OAAkYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRwAwBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEljGP8=").unwrap();
161
162        let cell = Boc::decode(&data).unwrap();
163        assert_eq!(cell.repr_hash(), &[
164            0x63, 0xd4, 0x75, 0x13, 0x9a, 0xc1, 0x4f, 0x3e, 0xfe, 0x69, 0x0e, 0xd7, 0xfd, 0x4f,
165            0xf0, 0x02, 0x1c, 0xf2, 0x6b, 0xc4, 0xab, 0xd0, 0xaf, 0x01, 0x40, 0xa3, 0xb4, 0xc8,
166            0x95, 0xf0, 0x73, 0x76
167        ]);
168
169        let serialized = Boc::encode(cell.as_ref());
170        assert_eq!(serialized, data);
171    }
172
173    #[test]
174    fn big_cell_deserialization() {
175        let data = decode_base64("te6ccgIDAAwAAQAAAACIAAAEBAABAAEAAQABAAEEBAACAAIAAgACAAIEBAADAAMAAwADAAMEBAAEAAQABAAEAAQEBAAFAAUABQAFAAUEBAAGAAYABgAGAAYEBAAHAAcABwAHAAcEBAAIAAgACAAIAAgEBAAJAAkACQAJAAkEBAAKAAoACgAKAAoEBAALAAsACwALAAsABAAA").unwrap();
176        let cell = Boc::decode(data).unwrap();
177
178        let stats = cell.compute_unique_stats(1 << 22).unwrap();
179        assert_eq!(stats, CellTreeStats {
180            bit_count: 192,
181            cell_count: 12
182        });
183    }
184
185    #[test]
186    fn test_builder() -> anyhow::Result<()> {
187        let parsed_cell = Boc::decode_base64("te6ccgEBAQEAAwAAAbE=")?;
188
189        let mut builder = CellBuilder::new();
190        builder.store_bit_one()?;
191        builder.store_bit_zero()?;
192        builder.store_bit_one()?;
193        builder.store_bit_one()?;
194        builder.store_bit_zero()?;
195        builder.store_bit_zero()?;
196        builder.store_bit_zero()?;
197        let built_cell = builder.build()?;
198
199        assert_eq!(parsed_cell.repr_hash(), built_cell.repr_hash());
200
201        let parsed_cell = Boc::decode_base64(
202            "te6ccgEBAQEAggAA////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////",
203        )?;
204
205        let mut builder = CellBuilder::new();
206        for _ in 0..MAX_BIT_LEN {
207            builder.store_bit_one()?;
208        }
209        assert!(builder.store_bit_one().is_err());
210        let built_cell = builder.build()?;
211
212        assert_eq!(parsed_cell.repr_hash(), built_cell.repr_hash());
213
214        let mut builder = CellBuilder::new();
215        builder.store_bit_one()?;
216        builder.store_u128(0xaaffaaffaaffaaffaaffaaffaaffaaff)?;
217        let cell = builder.build()?;
218
219        let mut builder = CellBuilder::new();
220        builder.store_bit_one()?;
221        builder.store_u64(0xaaffaaffaaffaaff)?;
222        builder.store_u64(0xaaffaaffaaffaaff)?;
223        assert_eq!(cell.as_ref(), builder.build()?.as_ref());
224
225        let mut builder = CellBuilder::new();
226        builder.store_zeros(1020)?;
227        builder.store_small_uint(0x5, 3)?;
228        builder.build()?;
229
230        let mut builder = CellBuilder::new();
231        builder.store_small_uint(5, 3)?;
232        builder.store_u256(HashBytes::wrap(&[
233            0xdf, 0x86, 0xce, 0xbc, 0xe8, 0xd5, 0xab, 0x0c, 0x69, 0xb4, 0xce, 0x33, 0xfe, 0x9b,
234            0x0e, 0x2c, 0xdf, 0x69, 0xa3, 0xe1, 0x13, 0x7e, 0x64, 0x85, 0x6b, 0xbc, 0xfd, 0x39,
235            0xe7, 0x9b, 0xc1, 0x6f,
236        ]))?;
237        let cell = builder.build()?;
238
239        let target_cell =
240            Boc::decode_base64("te6ccgEBAQEAIwAAQbvw2dedGrVhjTaZxn/TYcWb7TR8Im/MkK13n6c883gt8A==")?;
241        assert_eq!(cell.as_ref(), target_cell.as_ref());
242
243        let mut builder = CellBuilder::new();
244        builder.store_zeros(3)?;
245        builder.store_raw(&[0xdd, 0x55], 10)?;
246        builder.store_reference(target_cell)?;
247        builder.store_reference(cell)?;
248        let cell = builder.build()?;
249
250        let mut builder = CellBuilder::new();
251        builder.store_slice(cell.as_slice()?)?;
252        let cell = builder.build()?;
253        println!("{}", cell.display_tree());
254
255        Ok(())
256    }
257
258    #[test]
259    fn test_tx() {
260        let cell = Boc::decode_base64("te6ccgICAQoAAQAADGkAAAO3ea37gczcXLp00bkP3eA1txaTwX6TyzGtowSuHiFwobmgAAF3fHG0RBrAoqQhyfVHKxY+b4xigHnXHqftp9X5vfYVKuY58i4/cAABd3p8EkwWJgK1gAA0gEVmAigABQAEAAECEQyBbEYb1mwEQAADAAIAb8mHoSBMFFhAAAAAAAACAAAAAAADMQg15pv/2PjjbqZFi59+K/39f1kPXUGLckkscjpa2sJAUBYMAJ1D7gMTiAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAIJyl+oF61WYJFz0URNA5vMfkcc7dxHYfH6w0cmoXG2Ro2za6+U+LRtB2aSLAAMVTmTPucTOeWBEjz1nOjURo9Gg/wIB4AAIAAYBAd8ABwCxSAE1v3A5m4uXTpo3Ifu8Brbi0ngv0nlmNbRglcPELhQ3NQAxLah1y23nqb6T3ERREC7LXfYeMu26LwYH1Ht6c3lDQZDuaygABhRYYAAALu+ONoiExMBWsEABRYgBNb9wOZuLl06aNyH7vAa24tJ4L9J5ZjW0YJXDxC4UNzQMAAkB4fZ7eRCTQYwyOQPFDYjRpK0QMs7JDtGuaerLBmn2TDLl25hSY50SC7Nnc6gIFU3xYshpJ4j3tGtYPCPCMXRuJgTPXNlw4YdSq3zWEWMJOr0f83TQcuo2IkFjiPQacwNzkMAAAGAR6lJjmJgK5JM7mRsgAAoBZYAYltQ65bbz1N9J7iIoiBdlrvsPGXbdF4MD6j29ObyhoMAAAAAAAAAAAAAAAAdzWUAAOAALBAAADAAMAAwADAQAAA0ADQANAA0EAAAOAA4ADgAOBAAADwAPAA8ADwQAABAAEAAQABAEAAARABEAEQARBAAAEgASABIAEgQAABMAEwATABMEAAAUABQAFAAUBAAAFQAVABUAFQQAABYAFgAWABYEAAAXABcAFwAXBAAAGAAYABgAGAQAABkAGQAZABkEAAAaABoAGgAaBAAAGwAbABsAGwQAABwAHAAcABwEAAAdAB0AHQAdBAAAHgAeAB4AHgQAAB8AHwAfAB8EAAAgACAAIAAgBAAAIQAhACEAIQQAACIAIgAiACIEAAAjACMAIwAjBAAAJAAkACQAJAQAACUAJQAlACUEAAAmACYAJgAmBAAAJwAnACcAJwQAACgAKAAoACgEAAApACkAKQApBAAAKgAqACoAKgQAACsAKwArACsEAAAsACwALAAsBAAALQAtAC0ALQQAAC4ALgAuAC4EAAAvAC8ALwAvBAAAMAAwADAAMAQAADEAMQAxADEEAAAyADIAMgAyBAAAMwAzADMAMwQAADQANAA0ADQEAAA1ADUANQA1BAAANgA2ADYANgQAADcANwA3ADcEAAA4ADgAOAA4BAAAOQA5ADkAOQQAADoAOgA6ADoEAAA7ADsAOwA7BAAAPAA8ADwAPAQAAD0APQA9AD0EAAA+AD4APgA+BAAAPwA/AD8APwQAAEAAQABAAEAEAABBAEEAQQBBBAAAQgBCAEIAQgQAAEMAQwBDAEMEAABEAEQARABEBAAARQBFAEUARQQAAEYARgBGAEYEAABHAEcARwBHBAAASABIAEgASAQAAEkASQBJAEkEAABKAEoASgBKBAAASwBLAEsASwQAAEwATABMAEwEAABNAE0ATQBNBAAATgBOAE4ATgQAAE8ATwBPAE8EAABQAFAAUABQBAAAUQBRAFEAUQQAAFIAUgBSAFIEAABTAFMAUwBTBAAAVABUAFQAVAQAAFUAVQBVAFUEAABWAFYAVgBWBAAAVwBXAFcAVwQAAFgAWABYAFgEAABZAFkAWQBZBAAAWgBaAFoAWgQAAFsAWwBbAFsEAABcAFwAXABcBAAAXQBdAF0AXQQAAF4AXgBeAF4EAABfAF8AXwBfBAAAYABgAGAAYAQAAGEAYQBhAGEEAABiAGIAYgBiBAAAYwBjAGMAYwQAAGQAZABkAGQEAABlAGUAZQBlBAAAZgBmAGYAZgQAAGcAZwBnAGcEAABoAGgAaABoBAAAaQBpAGkAaQQAAGoAagBqAGoEAABrAGsAawBrBAAAbABsAGwAbAQAAG0AbQBtAG0EAABuAG4AbgBuBAAAbwBvAG8AbwQAAHAAcABwAHAEAABxAHEAcQBxBAAAcgByAHIAcgQAAHMAcwBzAHMEAAB0AHQAdAB0BAAAdQB1AHUAdQQAAHYAdgB2AHYEAAB3AHcAdwB3BAAAeAB4AHgAeAQAAHkAeQB5AHkEAAB6AHoAegB6BAAAewB7AHsAewQAAHwAfAB8AHwEAAB9AH0AfQB9BAAAfgB+AH4AfgQAAH8AfwB/AH8EAACAAIAAgACABAAAgQCBAIEAgQQAAIIAggCCAIIEAACDAIMAgwCDBAAAhACEAIQAhAQAAIUAhQCFAIUEAACGAIYAhgCGBAAAhwCHAIcAhwQAAIgAiACIAIgEAACJAIkAiQCJBAAAigCKAIoAigQAAIsAiwCLAIsEAACMAIwAjACMBAAAjQCNAI0AjQQAAI4AjgCOAI4EAACPAI8AjwCPBAAAkACQAJAAkAQAAJEAkQCRAJEEAACSAJIAkgCSBAAAkwCTAJMAkwQAAJQAlACUAJQEAACVAJUAlQCVBAAAlgCWAJYAlgQAAJcAlwCXAJcEAACYAJgAmACYBAAAmQCZAJkAmQQAAJoAmgCaAJoEAACbAJsAmwCbBAAAnACcAJwAnAQAAJ0AnQCdAJ0EAACeAJ4AngCeBAAAnwCfAJ8AnwQAAKAAoACgAKAEAAChAKEAoQChBAAAogCiAKIAogQAAKMAowCjAKMEAACkAKQApACkBAAApQClAKUApQQAAKYApgCmAKYEAACnAKcApwCnBAAAqACoAKgAqAQAAKkAqQCpAKkEAACqAKoAqgCqBAAAqwCrAKsAqwQAAKwArACsAKwEAACtAK0ArQCtBAAArgCuAK4ArgQAAK8ArwCvAK8EAACwALAAsACwBAAAsQCxALEAsQQAALIAsgCyALIEAACzALMAswCzBAAAtAC0ALQAtAQAALUAtQC1ALUEAAC2ALYAtgC2BAAAtwC3ALcAtwQAALgAuAC4ALgEAAC5ALkAuQC5BAAAugC6ALoAugQAALsAuwC7ALsEAAC8ALwAvAC8BAAAvQC9AL0AvQQAAL4AvgC+AL4EAAC/AL8AvwC/BAAAwADAAMAAwAQAAMEAwQDBAMEEAADCAMIAwgDCBAAAwwDDAMMAwwQAAMQAxADEAMQEAADFAMUAxQDFBAAAxgDGAMYAxgQAAMcAxwDHAMcEAADIAMgAyADIBAAAyQDJAMkAyQQAAMoAygDKAMoEAADLAMsAywDLBAAAzADMAMwAzAQAAM0AzQDNAM0EAADOAM4AzgDOBAAAzwDPAM8AzwQAANAA0ADQANAEAADRANEA0QDRBAAA0gDSANIA0gQAANMA0wDTANMEAADUANQA1ADUBAAA1QDVANUA1QQAANYA1gDWANYEAADXANcA1wDXBAAA2ADYANgA2AQAANkA2QDZANkEAADaANoA2gDaBAAA2wDbANsA2wQAANwA3ADcANwEAADdAN0A3QDdBAAA3gDeAN4A3gQAAN8A3wDfAN8EAADgAOAA4ADgBAAA4QDhAOEA4QQAAOIA4gDiAOIEAADjAOMA4wDjBAAA5ADkAOQA5AQAAOUA5QDlAOUEAADmAOYA5gDmBAAA5wDnAOcA5wQAAOgA6ADoAOgEAADpAOkA6QDpBAAA6gDqAOoA6gQAAOsA6wDrAOsEAADsAOwA7ADsBAAA7QDtAO0A7QQAAO4A7gDuAO4EAADvAO8A7wDvBAAA8ADwAPAA8AQAAPEA8QDxAPEEAADyAPIA8gDyBAAA8wDzAPMA8wQAAPQA9AD0APQEAAD1APUA9QD1BAAA9gD2APYA9gQAAPcA9wD3APcEAAD4APgA+AD4BAAA+QD5APkA+QQAAPoA+gD6APoEAAD7APsA+wD7BAAA/AD8APwA/AQAAP0A/QD9AP0EAAD+AP4A/gD+BAAA/wD/AP8A/wQAAQABAAEAAQAEAAEBAQEBAQEBBAABAgECAQIBAgQAAQMBAwEDAQMEAAEEAQQBBAEEBAABBQEFAQUBBQQAAQYBBgEGAQYEAAEHAQcBBwEHBAABCAEIAQgBCAQAAQkBCQEJAQkAAA==").unwrap();
261
262        let stats = cell.compute_unique_stats(1 << 22).unwrap();
263        assert_eq!(stats, CellTreeStats {
264            bit_count: 4681,
265            cell_count: 266
266        });
267    }
268}