Skip to content

Commit c26855a

Browse files
committed
Deduplicate cells in collated data during one validator session
1 parent bb0af68 commit c26855a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1907
-623
lines changed

create-hardfork/create-hardfork.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,9 @@ class HardforkCreator : public td::actor::Actor {
246246
}
247247
void send_shard_block_info(ton::BlockIdExt block_id, ton::CatchainSeqno cc_seqno, td::BufferSlice data) override {
248248
}
249-
void send_block_candidate(ton::BlockIdExt block_id, ton::CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
250-
td::BufferSlice data, int mode) override {
249+
void send_block_candidate_broadcast(ton::BlockIdExt block_id, ton::CatchainSeqno cc_seqno,
250+
td::uint32 validator_set_hash, td::BufferSlice data,
251+
td::optional<td::BufferSlice> collated_data, int mode) override {
251252
}
252253
void send_broadcast(ton::BlockBroadcast broadcast, int mode) override {
253254
}
@@ -277,6 +278,9 @@ class HardforkCreator : public td::actor::Actor {
277278
ton::ShardIdFull dst_shard, std::vector<ton::BlockIdExt> blocks, block::ImportedMsgQueueLimits limits,
278279
td::Timestamp timeout, td::Promise<std::vector<td::Ref<ton::validator::OutMsgQueueProof>>> promise) override {
279280
}
281+
void download_block_candidate(ton::BlockIdExt block_id, bool only_collated_data, td::Timestamp timeout,
282+
td::Promise<std::pair<td::BufferSlice, td::BufferSlice>> promise) override {
283+
}
280284

281285
void new_key_block(ton::validator::BlockHandle handle) override {
282286
}

crypto/block/block.tlb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ block_info#9bc7a987 version:uint32
451451
after_split:(## 1)
452452
want_split:Bool want_merge:Bool
453453
key_block:Bool vert_seqno_incr:(## 1)
454-
flags:(## 8) { flags <= 1 }
454+
flags:(## 8) { flags <= 3 }
455455
seq_no:# vert_seq_no:# { vert_seq_no >= vert_seqno_incr }
456456
{ prev_seq_no:# } { ~prev_seq_no + 1 = seq_no }
457457
shard:ShardIdent gen_utime:uint32
@@ -464,6 +464,7 @@ block_info#9bc7a987 version:uint32
464464
master_ref:not_master?^BlkMasterInfo
465465
prev_ref:^(BlkPrevInfo after_merge)
466466
prev_vert_ref:vert_seqno_incr?^(BlkPrevInfo 0)
467+
collated_data_hash:flags . 1?bits256
467468
= BlockInfo;
468469

469470
prev_blk_info$_ prev:ExtBlkRef = BlkPrevInfo 0;
@@ -772,7 +773,7 @@ consensus_config_v3#d8 flags:(## 7) { flags = 0 } new_catchain_ids:Bool
772773
max_block_bytes:uint32 max_collated_bytes:uint32
773774
proto_version:uint16 = ConsensusConfig;
774775

775-
consensus_config_v4#d9 flags:(## 7) { flags = 0 } new_catchain_ids:Bool
776+
consensus_config_v4#d9 flags:(## 6) { flags = 0 } merge_collated_data:Bool new_catchain_ids:Bool
776777
round_candidates:(## 8) { round_candidates >= 1 }
777778
next_candidate_delay_ms:uint32 consensus_timeout_ms:uint32
778779
fast_attempts:uint32 attempt_duration:uint32 catchain_max_deps:uint32
@@ -857,6 +858,9 @@ top_block_descr#d5 proof_for:BlockIdExt signatures:(Maybe ^BlockSignatures)
857858
//
858859
top_block_descr_set#4ac789f3 collection:(HashmapE 96 ^TopBlockDescr) = TopBlockDescrSet;
859860
account_storage_dict_proof#37c1e3fc proof:^Cell = AccountStorageDictProof;
861+
collated_data_root_state#4b2f36ec hash:bits256 = CollatedDataRootState;
862+
collated_data_root_storage_dict#796eaeb6 hash:bits256 = CollatedDataRootStorageDict;
863+
collated_data_separator#fa8b2b92 = CollatedDataSeparator;
860864

861865
//
862866
// VALIDATOR MISBEHAVIOR COMPLAINTS

crypto/block/mc-config.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ ton::ValidatorSessionConfig Config::get_consensus_config() const {
336336
td::uint64 catchain_lifetime = std::max(catchain_config.mc_cc_lifetime, catchain_config.shard_cc_lifetime);
337337
c.catchain_opts.max_block_height_coeff = catchain_lifetime * max_blocks_coeff;
338338
}
339+
c.merge_collated_data = r.merge_collated_data;
339340
};
340341
if (cc.not_null()) {
341342
block::gen::ConsensusConfig::Record_consensus_config_v4 r4;

crypto/common/refcnt.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,14 @@ class Ref {
285285
Ref& operator=(Ref<S>&& r);
286286
const typename RefValue<T>::Type* operator->() const {
287287
if (!ptr) {
288-
CHECK(ptr && "deferencing null Ref");
288+
LOG_CHECK(ptr) << "dereferencing null Ref<" << typeid(T).name() << ">";
289289
throw NullRef{};
290290
}
291291
return RefValue<T>::make_const_ptr(ptr);
292292
}
293293
const typename RefValue<T>::Type& operator*() const {
294294
if (!ptr) {
295-
CHECK(ptr && "deferencing null Ref");
295+
LOG_CHECK(ptr) << "dereferencing null Ref<" << typeid(T).name() << ">";
296296
throw NullRef{};
297297
}
298298
return RefValue<T>::make_const_ref(ptr);
@@ -308,7 +308,7 @@ class Ref {
308308
}
309309
bool is_unique() const {
310310
if (!ptr) {
311-
CHECK(ptr && "defererencing null Ref");
311+
LOG_CHECK(ptr) << "dereferencing null Ref<" << typeid(T).name() << ">";
312312
throw NullRef{};
313313
}
314314
return ptr->is_unique();

crypto/vm/boc-compression.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ td::Result<std::vector<td::Ref<vm::Cell>>> boc_decompress_baseline_lz4(td::Slice
5757
}
5858

5959
TRY_RESULT(decompressed, td::lz4_decompress(compressed, decompressed_size));
60-
TRY_RESULT(roots, vm::std_boc_deserialize_multi(decompressed));
60+
TRY_RESULT(roots, vm::std_boc_deserialize_multi(decompressed, 1000000, true));
6161
return roots;
6262
}
6363

crypto/vm/boc.cpp

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
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

12671270
void 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

12871292
void 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-
13011304
td::uint64 ProofStorageStat::estimate_proof_size() const {
13021305
return proof_size_;
13031306
}
13041307

13051308
ProofStorageStat::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

13101362
td::uint64 ProofStorageStat::estimate_prunned_size() {

crypto/vm/boc.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,19 @@ class ProofStorageStat {
177177
return get_cell_status(hash) == c_loaded;
178178
}
179179

180+
std::vector<Ref<Cell>> build_collated_data() const;
181+
180182
static td::uint64 estimate_prunned_size();
181183
static td::uint64 estimate_serialized_size(const Ref<DataCell>& cell);
182184

183185
private:
184-
td::HashMap<Cell::Hash, std::pair<CellStatus, td::uint64>> cells_;
186+
struct CellInfo {
187+
Ref<DataCell> cell; // only for c_loaded
188+
td::uint8 cell_max_level = Cell::max_level; // only for c_loaded
189+
CellStatus status = c_none;
190+
td::uint64 serialized_size = 0;
191+
};
192+
td::HashMap<Cell::Hash, CellInfo> cells_;
185193
td::uint64 proof_size_ = 0;
186194
};
187195

@@ -400,7 +408,8 @@ td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty = fa
400408
td::Result<td::BufferSlice> std_boc_serialize(Ref<Cell> root, int mode = 0);
401409

402410
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data,
403-
int max_roots = BagOfCells::default_max_roots);
411+
int max_roots = BagOfCells::default_max_roots,
412+
bool allow_nonzero_level = false);
404413
td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> root, int mode = 0);
405414

406415
td::Status std_boc_serialize_to_file(Ref<Cell> root, td::FileFd& fd, int mode = 0,

crypto/vm/cells/ExtCell.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@ class ExtCell : public Cell {
6868
Ref<PrunnedCell<ExtraT>> get_prunned_cell() const {
6969
return prunned_cell_.load();
7070
}
71+
td::Status set_inner_cell(Ref<DataCell> new_cell) const {
72+
auto prunned_cell = prunned_cell_.load();
73+
if (prunned_cell.is_null()) {
74+
return td::Status::OK();
75+
}
76+
TRY_STATUS(prunned_cell->check_equals_unloaded(new_cell));
77+
if (data_cell_.store_if_empty(new_cell)) {
78+
prunned_cell_.store({});
79+
get_thread_safe_counter_unloaded().add(-1);
80+
}
81+
return td::Status::OK();
82+
}
7183

7284
private:
7385
mutable td::AtomicRef<DataCell> data_cell_;

overlay/overlay-peers.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,12 +508,16 @@ void OverlayImpl::get_overlay_random_peers(td::uint32 max_peers,
508508
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) {
509509
std::vector<adnl::AdnlNodeIdShort> v;
510510
auto t = td::Clocks::system();
511-
while (v.size() < max_peers && v.size() < peer_list_.peers_.size() - peer_list_.bad_peers_.size()) {
511+
td::uint32 iters = 0;
512+
while (v.size() < max_peers && v.size() < peer_list_.peers_.size() - peer_list_.bad_peers_.size() &&
513+
iters <= peer_list_.peers_.size() * 2) {
514+
++iters;
512515
auto P = peer_list_.peers_.get_random();
513516
if (!P->is_permanent_member() && (P->get_version() + 3600 < t || P->certificate()->is_expired(t))) {
514517
VLOG(OVERLAY_INFO) << this << ": deleting outdated peer " << P->get_id();
515518
del_peer(P->get_id());
516-
} else if (P->is_alive()) {
519+
} else if (P->is_alive() && P->get_id() != local_id_ &&
520+
!(P->get_node()->flags() & OverlayMemberFlags::DoNotReceiveBroadcasts)) {
517521
bool dup = false;
518522
for (auto &n : v) {
519523
if (n == P->get_id()) {

tdutils/td/utils/LRUCache.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ class LRUCache {
8686
return result;
8787
}
8888

89+
void remove(const K& key) {
90+
auto it = cache_.find(key);
91+
if (it == cache_.end()) {
92+
return;
93+
}
94+
total_weight_ -= (*it)->weight;
95+
(*it)->remove();
96+
cache_.erase(it);
97+
}
98+
99+
89100
private:
90101
struct Entry : ListNode {
91102
Entry(K key, uint64 weight) : key(std::move(key)), weight(weight) {

0 commit comments

Comments
 (0)