mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Limit maximal Merkle depth (#626)
This commit is contained in:
parent
0578cb4a42
commit
706be23c83
12 changed files with 196 additions and 84 deletions
|
@ -1008,27 +1008,40 @@ td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> roots
|
|||
*
|
||||
*/
|
||||
|
||||
bool CellStorageStat::compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cs_ref), kill_dup, skip_count_root) && clear_seen();
|
||||
TRY_RESULT(res, add_used_storage(std::move(cs_ref), kill_dup, skip_count_root));
|
||||
clear_seen();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(cs, kill_dup, skip_count_root) && clear_seen();
|
||||
TRY_RESULT(res, add_used_storage(cs, kill_dup, skip_count_root));
|
||||
clear_seen();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cs), kill_dup, skip_count_root) && clear_seen();
|
||||
TRY_RESULT(res, add_used_storage(std::move(cs), kill_dup, skip_count_root));
|
||||
clear_seen();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::compute_used_storage(Ref<vm::Cell> cell, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::compute_used_storage(Ref<vm::Cell> cell, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
clear();
|
||||
return add_used_storage(std::move(cell), kill_dup, skip_count_root) && clear_seen();
|
||||
TRY_RESULT(res, add_used_storage(std::move(cell), kill_dup, skip_count_root));
|
||||
clear_seen();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
if (cs_ref->is_unique()) {
|
||||
return add_used_storage(std::move(cs_ref.unique_write()), kill_dup, skip_count_root);
|
||||
} else {
|
||||
|
@ -1036,56 +1049,67 @@ bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
|
|||
}
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
if (!(skip_count_root & 1)) {
|
||||
++cells;
|
||||
if (cells > limit_cells) {
|
||||
return false;
|
||||
return td::Status::Error("too many cells");
|
||||
}
|
||||
}
|
||||
if (!(skip_count_root & 2)) {
|
||||
bits += cs.size();
|
||||
if (bits > limit_bits) {
|
||||
return false;
|
||||
return td::Status::Error("too many bits");
|
||||
}
|
||||
}
|
||||
CellInfo res;
|
||||
for (unsigned i = 0; i < cs.size_refs(); i++) {
|
||||
if (!add_used_storage(cs.prefetch_ref(i), kill_dup)) {
|
||||
return false;
|
||||
}
|
||||
TRY_RESULT(child, add_used_storage(cs.prefetch_ref(i), kill_dup));
|
||||
res.max_merkle_depth = std::max(res.max_merkle_depth, child.max_merkle_depth);
|
||||
}
|
||||
return true;
|
||||
if (cs.special_type() == CellTraits::SpecialType::MerkleProof ||
|
||||
cs.special_type() == CellTraits::SpecialType::MerkleUpdate) {
|
||||
++res.max_merkle_depth;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
if (!(skip_count_root & 1)) {
|
||||
++cells;
|
||||
if (cells > limit_cells) {
|
||||
return false;
|
||||
return td::Status::Error("too many cells");
|
||||
}
|
||||
}
|
||||
if (!(skip_count_root & 2)) {
|
||||
bits += cs.size();
|
||||
if (bits > limit_bits) {
|
||||
return false;
|
||||
return td::Status::Error("too many bits");
|
||||
}
|
||||
}
|
||||
CellInfo res;
|
||||
while (cs.size_refs()) {
|
||||
if (!add_used_storage(cs.fetch_ref(), kill_dup)) {
|
||||
return false;
|
||||
}
|
||||
TRY_RESULT(child, add_used_storage(cs.fetch_ref(), kill_dup));
|
||||
res.max_merkle_depth = std::max(res.max_merkle_depth, child.max_merkle_depth);
|
||||
}
|
||||
return true;
|
||||
if (cs.special_type() == CellTraits::SpecialType::MerkleProof ||
|
||||
cs.special_type() == CellTraits::SpecialType::MerkleUpdate) {
|
||||
++res.max_merkle_depth;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CellStorageStat::add_used_storage(Ref<vm::Cell> cell, bool kill_dup, unsigned skip_count_root) {
|
||||
td::Result<CellStorageStat::CellInfo> CellStorageStat::add_used_storage(Ref<vm::Cell> cell, bool kill_dup,
|
||||
unsigned skip_count_root) {
|
||||
if (cell.is_null()) {
|
||||
return false;
|
||||
return td::Status::Error("cell is null");
|
||||
}
|
||||
if (kill_dup) {
|
||||
auto ins = seen.insert(cell->get_hash());
|
||||
auto ins = seen.emplace(cell->get_hash(), CellInfo{});
|
||||
if (!ins.second) {
|
||||
return true;
|
||||
return ins.first->second;
|
||||
}
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVm{}, std::move(cell)};
|
||||
|
|
|
@ -108,12 +108,14 @@ struct CellStorageStat {
|
|||
unsigned long long cells;
|
||||
unsigned long long bits;
|
||||
unsigned long long public_cells;
|
||||
std::set<vm::Cell::Hash> seen;
|
||||
struct CellInfo {
|
||||
td::uint32 max_merkle_depth = 0;
|
||||
};
|
||||
std::map<vm::Cell::Hash, CellInfo> seen;
|
||||
CellStorageStat() : cells(0), bits(0), public_cells(0) {
|
||||
}
|
||||
bool clear_seen() {
|
||||
void clear_seen() {
|
||||
seen.clear();
|
||||
return true;
|
||||
}
|
||||
void clear() {
|
||||
cells = bits = public_cells = 0;
|
||||
|
@ -124,15 +126,16 @@ struct CellStorageStat {
|
|||
limit_cells = std::numeric_limits<unsigned long long>::max();
|
||||
limit_bits = std::numeric_limits<unsigned long long>::max();
|
||||
}
|
||||
bool compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool compute_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true,
|
||||
unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> compute_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
|
||||
bool add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
bool add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
td::Result<CellInfo> add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
|
||||
|
||||
unsigned long long limit_cells = std::numeric_limits<unsigned long long>::max();
|
||||
unsigned long long limit_bits = std::numeric_limits<unsigned long long>::max();
|
||||
|
|
|
@ -39,7 +39,13 @@ class MerkleProofImpl {
|
|||
dfs_usage_tree(cell, usage_tree_->root_id());
|
||||
is_prunned_ = [this](const Ref<Cell> &cell) { return visited_cells_.count(cell->get_hash()) == 0; };
|
||||
}
|
||||
return dfs(cell, cell->get_level());
|
||||
try {
|
||||
return dfs(cell, cell->get_level());
|
||||
} catch (CellBuilder::CellWriteError &) {
|
||||
return {};
|
||||
} catch (CellBuilder::CellCreateError &) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -119,6 +125,9 @@ Ref<Cell> MerkleProof::generate(Ref<Cell> cell, CellUsageTree *usage_tree) {
|
|||
return {};
|
||||
}
|
||||
auto raw = generate_raw(std::move(cell), usage_tree);
|
||||
if (raw.is_null()) {
|
||||
return {};
|
||||
}
|
||||
return CellBuilder::create_merkle_proof(std::move(raw));
|
||||
}
|
||||
|
||||
|
@ -384,21 +393,29 @@ bool MerkleProofBuilder::clear() {
|
|||
return true;
|
||||
}
|
||||
|
||||
Ref<Cell> MerkleProofBuilder::extract_proof() const {
|
||||
return MerkleProof::generate(orig_root, usage_tree.get());
|
||||
td::Result<Ref<Cell>> MerkleProofBuilder::extract_proof() const {
|
||||
Ref<Cell> proof = MerkleProof::generate(orig_root, usage_tree.get());
|
||||
if (proof.is_null()) {
|
||||
return td::Status::Error("cannot create Merkle proof");
|
||||
}
|
||||
return proof;
|
||||
}
|
||||
|
||||
bool MerkleProofBuilder::extract_proof_to(Ref<Cell> &proof_root) const {
|
||||
return orig_root.not_null() && (proof_root = extract_proof()).not_null();
|
||||
if (orig_root.is_null()) {
|
||||
return false;
|
||||
}
|
||||
auto R = extract_proof();
|
||||
if (R.is_error()) {
|
||||
return false;
|
||||
}
|
||||
proof_root = R.move_as_ok();
|
||||
return true;
|
||||
}
|
||||
|
||||
td::Result<td::BufferSlice> MerkleProofBuilder::extract_proof_boc() const {
|
||||
Ref<Cell> proof_root = extract_proof();
|
||||
if (proof_root.is_null()) {
|
||||
return td::Status::Error("cannot create Merkle proof");
|
||||
} else {
|
||||
return std_boc_serialize(std::move(proof_root));
|
||||
}
|
||||
TRY_RESULT(proof_root, extract_proof());
|
||||
return std_boc_serialize(std::move(proof_root));
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -63,7 +63,7 @@ class MerkleProofBuilder {
|
|||
Ref<Cell> root() const {
|
||||
return usage_root;
|
||||
}
|
||||
Ref<Cell> extract_proof() const;
|
||||
td::Result<Ref<Cell>> extract_proof() const;
|
||||
bool extract_proof_to(Ref<Cell> &proof_root) const;
|
||||
td::Result<td::BufferSlice> extract_proof_boc() const;
|
||||
};
|
||||
|
|
|
@ -221,6 +221,9 @@ Ref<Cell> MerkleUpdate::generate(Ref<Cell> from, Ref<Cell> to, CellUsageTree *us
|
|||
return {};
|
||||
}
|
||||
auto res = generate_raw(std::move(from), std::move(to), usage_tree);
|
||||
if (res.first.is_null() || res.second.is_null()) {
|
||||
return {};
|
||||
}
|
||||
return CellBuilder::create_merkle_update(res.first, res.second);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue