tonlib_core/library_helper/
helper.rs1use 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}