2020#include < iomanip>
2121#include < algorithm>
2222#include " vm/boc.h"
23+
24+ #include " cells/MerkleProof.h"
25+ #include " cells/PrunnedCell.h"
2326#include " vm/boc-writers.h"
2427#include " vm/cells.h"
2528#include " vm/cellslice.h"
@@ -973,7 +976,7 @@ td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty, boo
973976 return std::move (root);
974977}
975978
976- td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi (td::Slice data, int max_roots) {
979+ td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi (td::Slice data, int max_roots, bool allow_nonzero_level ) {
977980 if (data.empty ()) {
978981 return std::vector<Ref<Cell>>{};
979982 }
@@ -989,7 +992,7 @@ td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data, int
989992 if (root.is_null ()) {
990993 return td::Status::Error (" bag of cells has a null root cell (?)" );
991994 }
992- if (root->get_level () != 0 ) {
995+ if (!allow_nonzero_level && root->get_level () != 0 ) {
993996 return td::Status::Error (" bag of cells has a root with non-zero level" );
994997 }
995998 roots.emplace_back (std::move (root));
@@ -1265,46 +1268,95 @@ bool VmStorageStat::add_storage(const CellSlice& cs) {
12651268}
12661269
12671270void ProofStorageStat::add_loaded_cell (const Ref<DataCell>& cell, td::uint8 max_level) {
1268- max_level = std::min<td::uint32 >(max_level, Cell::max_level);
1269- auto & [status, size] = cells_[cell->get_hash (max_level)];
1270- if (status == c_loaded) {
1271+ max_level = std::min<td::uint8 >(max_level, Cell::max_level);
1272+ auto & info = cells_[cell->get_hash (max_level)];
1273+ if (info. status == c_loaded) {
12711274 return ;
12721275 }
1273- proof_size_ -= size;
1274- status = c_loaded;
1275- proof_size_ += size = estimate_serialized_size (cell);
1276+ proof_size_ -= info.serialized_size ;
1277+ info.status = c_loaded;
1278+ info.cell = cell;
1279+ info.cell_max_level = max_level;
1280+ proof_size_ += info.serialized_size = estimate_serialized_size (cell);
12761281 max_level += (cell->special_type () == CellTraits::SpecialType::MerkleProof ||
12771282 cell->special_type () == CellTraits::SpecialType::MerkleUpdate);
12781283 for (unsigned i = 0 ; i < cell->size_refs (); ++i) {
1279- auto & [child_status, child_size] = cells_[cell->get_ref (i)->get_hash (max_level)];
1280- if (child_status == c_none) {
1281- child_status = c_prunned;
1282- proof_size_ += child_size = estimate_prunned_size ();
1284+ auto & child = cells_[cell->get_ref (i)->get_hash (max_level)];
1285+ if (child. status == c_none) {
1286+ child. status = c_prunned;
1287+ proof_size_ += child. serialized_size = estimate_prunned_size ();
12831288 }
12841289 }
12851290}
12861291
12871292void ProofStorageStat::add_loaded_cells (const ProofStorageStat& other) {
1288- for (const auto & [hash, x] : other.cells_ ) {
1289- const auto & [new_status, new_size] = x;
1290- auto & [old_status, old_size] = cells_[hash];
1291- if (old_status >= new_status) {
1293+ for (const auto & [hash, new_info] : other.cells_ ) {
1294+ auto & old_info = cells_[hash];
1295+ if (old_info.status >= new_info.status ) {
12921296 continue ;
12931297 }
1294- proof_size_ -= old_size ;
1295- old_status = new_status ;
1296- proof_size_ += old_size = new_size ;
1298+ proof_size_ -= old_info. serialized_size ;
1299+ old_info = new_info ;
1300+ proof_size_ += old_info. serialized_size ;
12971301 }
12981302}
12991303
1300-
13011304td::uint64 ProofStorageStat::estimate_proof_size () const {
13021305 return proof_size_;
13031306}
13041307
13051308ProofStorageStat::CellStatus ProofStorageStat::get_cell_status (const Cell::Hash& hash) const {
13061309 auto it = cells_.find (hash);
1307- return it == cells_.end () ? c_none : it->second .first ;
1310+ return it == cells_.end () ? c_none : it->second .status ;
1311+ }
1312+
1313+ std::vector<Ref<Cell>> ProofStorageStat::build_collated_data () const {
1314+ struct Cache {
1315+ Ref<Cell> result;
1316+ bool is_root = true ;
1317+ };
1318+ std::map<Cell::Hash, Cache> cache;
1319+ std::function<Cache&(const CellInfo&)> dfs = [&](const CellInfo& info) -> Cache& {
1320+ Cell::Hash hash = info.cell ->get_hash (info.cell_max_level );
1321+ Cache& entry = cache[hash];
1322+ if (entry.result .not_null ()) {
1323+ return entry;
1324+ }
1325+ CellBuilder cb;
1326+ cb.store_bits (info.cell ->get_data (), info.cell ->size ());
1327+ td::uint8 child_max_level = info.cell_max_level ;
1328+ if (info.cell ->special_type () == CellTraits::SpecialType::MerkleProof ||
1329+ info.cell ->special_type () == CellTraits::SpecialType::MerkleUpdate) {
1330+ ++child_max_level;
1331+ }
1332+ for (unsigned i = 0 ; i < info.cell ->size_refs (); ++i) {
1333+ Ref<Cell> child = info.cell ->get_ref (i);
1334+ Cell::Hash child_hash = child->get_hash (child_max_level);
1335+ auto it = cells_.find (child_hash);
1336+ if (it == cells_.end () || it->second .status != c_loaded) {
1337+ cb.store_ref (CellBuilder::create_pruned_branch (child, Cell::max_level, child_max_level));
1338+ } else {
1339+ Cache& child_result = dfs (it->second );
1340+ child_result.is_root = false ;
1341+ cb.store_ref (child_result.result );
1342+ }
1343+ }
1344+ Cache& entry2 = cache[hash];
1345+ entry2.result = cb.finalize (info.cell ->is_special ());
1346+ return entry2;
1347+ };
1348+ for (auto & [_, info] : cells_) {
1349+ if (info.status == c_loaded) {
1350+ dfs (info);
1351+ }
1352+ }
1353+ std::vector<Ref<Cell>> result;
1354+ for (auto & [_, entry] : cache) {
1355+ if (entry.is_root ) {
1356+ result.push_back (std::move (entry.result ));
1357+ }
1358+ }
1359+ return result;
13081360}
13091361
13101362td::uint64 ProofStorageStat::estimate_prunned_size () {
0 commit comments