tonlib_core/library_helper/
helper.rs

1use std::collections::{HashMap, HashSet, VecDeque};
2
3use super::{ContractLibraryDict, TonLibraryError};
4use crate::cell::dict::predefined_writers::val_writer_ref_cell;
5use crate::cell::{ArcCell, BagOfCells, CellBuilder};
6use crate::TonHash;
7
8pub struct LibraryHelper;
9
10impl LibraryHelper {
11    pub fn store_to_dict(
12        lib_hashmap: HashMap<TonHash, ArcCell>,
13    ) -> Result<ContractLibraryDict, TonLibraryError> {
14        if lib_hashmap.is_empty() {
15            return Ok(ContractLibraryDict::new(vec![]));
16        }
17
18        let lib_cell = CellBuilder::new()
19            .store_dict_data(256, val_writer_ref_cell, lib_hashmap)?
20            .build()?;
21
22        let dict_boc = BagOfCells::from_root(lib_cell).serialize(false)?;
23        let dict = ContractLibraryDict::new(dict_boc);
24        Ok(dict)
25    }
26
27    pub fn extract_library_hashes<'a, I>(cells: I) -> Result<Vec<TonHash>, TonLibraryError>
28    where
29        I: IntoIterator<Item = &'a ArcCell>,
30    {
31        let mut arc_cell_buffer = VecDeque::new();
32
33        arc_cell_buffer.extend(cells);
34
35        let mut lib_cells = HashSet::new();
36        let mut visited_cells = HashSet::new();
37
38        while let Some(cell) = arc_cell_buffer.pop_front() {
39            if !visited_cells.insert(cell) {
40                continue;
41            }
42            let refs = cell.references();
43            arc_cell_buffer.extend(refs.iter());
44            if cell.is_library() {
45                lib_cells.insert(cell.clone());
46            }
47        }
48
49        let lib_hashes: Vec<TonHash> = lib_cells
50            .iter()
51            .map(|i| i.data()[1..].try_into())
52            .collect::<Result<_, _>>()?;
53
54        Ok(lib_hashes)
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use std::collections::HashSet;
61
62    use tokio_test::assert_ok;
63
64    use crate::cell::BagOfCells;
65    use crate::library_helper::LibraryHelper;
66    use crate::TonHash;
67
68    #[test]
69    fn test_get_lib_hashes_by_code() -> anyhow::Result<()> {
70        let boc = hex::decode("b5ee9c72410101010023000842029f31f4f413a3accb706c88962ac69d59103b013a0addcfaeed5dd73c18fa98a866a5f879")?;
71        let expected_lib_id =
72            TonHash::from_hex("9f31f4f413a3accb706c88962ac69d59103b013a0addcfaeed5dd73c18fa98a8")?;
73        let code = BagOfCells::parse(&boc)?.single_root()?;
74        let hashes = assert_ok!(LibraryHelper::extract_library_hashes(&[code]));
75
76        assert_eq!(hashes.len(), 1);
77        assert_eq!(expected_lib_id, hashes[0]);
78
79        Ok(())
80    }
81
82    #[test]
83    fn test_extract_libs_hashes_from_account() -> anyhow::Result<()> {
84        let account_cell = BagOfCells::parse_base64("te6ccgEBBAEA8wACbcALnBIxv16jVmxIK1r2UBfaInVF/ZiTIhIyZW89zjsyXFIIgXjDL67PEAAApNBf1c0o5iWgE0ADAQHLgBLkVbrIrEt2yaFK2bjvr7ukFMs9NiXFIQeFNZHUl39csAPKdF6IJ4rzGUpFtgCumniPLNm4Xr61h+EUzQ7m6U6zkgBbNNH1WCqtrdoD1I2iZsPakLqhenpsHNvLIVoFAC8ac5f8AgBTgB2Yx8zNOMlmFnXq0509cH0dbbfJexGwQoAdrI1BSXULYF9eEAC+vCAQCEIC8F5zC6xlKwQUtGc2RJmcgbi9KFlYBMAU/fgHgoJ5lyk=")?.single_root()?;
85
86        let expected_hash =
87            TonHash::from_hex("f05e730bac652b0414b4673644999c81b8bd28595804c014fdf8078282799729")?;
88        let hashes = LibraryHelper::extract_library_hashes(&[account_cell])?;
89        assert_eq!([expected_hash], hashes.as_slice());
90        Ok(())
91    }
92
93    #[test]
94    fn test_extract_libs_hashes_from_tx() -> anyhow::Result<()> {
95        let tx_cell = BagOfCells::parse_base64("te6ccgECDwEAAwIAA7V7nBIxv16jVmxIK1r2UBfaInVF/ZiTIhIyZW89zjsyXFAAApNHjvgAGEQXStaTphNowXid2UrUP36WDrzwLiBnIAdPV/U5Nn4AAAKTQX9XNIZfX1UAADR1FsgIBQQBAhkEgF4JAsnmyhh0c9cRAwIAb8mHoSBMFFhAAAAAAAACAAAAAAADGN3lQzL4zq6hI/88sLWZIBMzC7WNYeJBkUVxatc74GBAUBcMAJ5FPGwLbCQAAAAAAAAAAScAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIJyZKZhyT+7yUFKUgAlQcP6fYA6vuPZJ3iavbRwpvRXkaLpxCmiu6kCFcIf9iDkMi+QzAWWce3or9ccVakMUVmEJwIB4AgGAQHfBwC5aAFzgkY369RqzYkFa17KAvtETqi/sxJkQkZMree5x2ZLiwAlyKt1kViW7ZNClbNx3193SCmWemxLikIPCmsjqS7+uVAp0ujABhRYYAAAUmjx3wAEy+vqoB1KHnNAArFoAeU6L0QTxXmMpSLbAFdNPEeWbNwvX1rD8Ipmh3N0p1nJAC5wSMb9eo1ZsSCta9lAX2iJ1Rf2YkyISMmVvPc47MlxUCyebKAGRvwEAABSaPBSRYTL6+pB4AwJAl9uPE8JwA7MY+ZmnGSzCzr1ac6euD6OttvkvYjYIUAO1kagpLqFujmEP0MUdJPyDIILCgApAAAAAb8I6wBl9fYJAwCuM0M2BgBACEIC8F5zC6xlKwQUtGc2RJmcgbi9KFlYBMAU/fgHgoJ5lykCATQODQDLgBLkVbrIrEt2yaFK2bjvr7ukFMs9NiXFIQeFNZHUl39csAPKdF6IJ4rzGUpFtgCumniPLNm4Xr61h+EUzQ7m6U6zkgBbNNH1WCqtrdoD1I2iZsPakLqhenpsHNvLIVoFAC8ac4f8CEICcmEyBp1jWPl1TYnsWJ5gUk5EnB0PEQTb4dSXIG+LspA=")?.single_root()?;
96
97        let expected_hashes = HashSet::from([
98            TonHash::from_hex("f05e730bac652b0414b4673644999c81b8bd28595804c014fdf8078282799729")?,
99            TonHash::from_hex("726132069d6358f9754d89ec589e60524e449c1d0f1104dbe1d497206f8bb290")?,
100        ]);
101        let hashes = HashSet::from_iter(LibraryHelper::extract_library_hashes(&[tx_cell])?);
102        assert_eq!(hashes, expected_hashes);
103
104        Ok(())
105    }
106}