tonlib-client 0.23.1

Thin wrapper for tonlibjson
use std::collections::{HashMap, HashSet, VecDeque};

use tonlib_core::cell::dict::predefined_writers::val_writer_ref_cell;
use tonlib_core::cell::{ArcCell, BagOfCells, CellBuilder};
use tonlib_core::TonHash;

use super::ContractLibraryDict;
use crate::contract::TonLibraryError;

pub struct LibraryHelper;

impl LibraryHelper {
    pub fn store_to_dict(
        library_hashes: &[TonHash],
        lib_hashmap: HashMap<TonHash, ArcCell>,
    ) -> Result<ContractLibraryDict, TonLibraryError> {
        let lib_cell = CellBuilder::new()
            .store_dict_data(256, val_writer_ref_cell, lib_hashmap)?
            .build()?;

        let dict_boc = BagOfCells::from_root(lib_cell).serialize(false)?;
        let keys = library_hashes.to_vec();
        let dict = ContractLibraryDict { dict_boc, keys };
        Ok(dict)
    }

    pub fn extract_library_hashes<'a, I>(cells: I) -> Result<Vec<TonHash>, TonLibraryError>
    where
        I: IntoIterator<Item = &'a ArcCell>,
    {
        let mut arc_cell_buffer = VecDeque::new();

        arc_cell_buffer.extend(cells);

        let mut lib_cells = HashSet::new();
        let mut visited_cells = HashSet::new();

        while let Some(cell) = arc_cell_buffer.pop_front() {
            if !visited_cells.insert(cell) {
                continue;
            }
            let refs = cell.references();
            arc_cell_buffer.extend(refs.iter());
            if cell.is_library() {
                lib_cells.insert(cell.clone());
            }
        }

        let lib_hashes: Vec<TonHash> = lib_cells
            .iter()
            .map(|i| i.data()[1..].try_into())
            .collect::<Result<_, _>>()?;

        Ok(lib_hashes)
    }
}

#[cfg(test)]
mod tests {

    use tokio_test::assert_ok;
    use tonlib_core::cell::BagOfCells;
    use tonlib_core::TonHash;

    use crate::contract::LibraryHelper;

    #[test]
    fn test_get_lib_hashes_by_code() -> anyhow::Result<()> {
        let boc =hex::decode("b5ee9c72410101010023000842029f31f4f413a3accb706c88962ac69d59103b013a0addcfaeed5dd73c18fa98a866a5f879").unwrap();
        let expected_lib_id =
            TonHash::from_hex("9f31f4f413a3accb706c88962ac69d59103b013a0addcfaeed5dd73c18fa98a8")
                .unwrap();
        let code = BagOfCells::parse(&boc)?.into_single_root()?;
        let hashes = assert_ok!(LibraryHelper::extract_library_hashes(&[code]));

        assert_eq!(hashes.len(), 1);
        assert_eq!(expected_lib_id, hashes[0]);

        Ok(())
    }
}