Skip to content

Commit f416812

Browse files
committed
Optimistic validation
1 parent e169659 commit f416812

File tree

10 files changed

+324
-96
lines changed

10 files changed

+324
-96
lines changed

validator-session/validator-session.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,13 +294,24 @@ void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice
294294
<< "]: duplicate optimistic broadcast for round " << block_round;
295295
return;
296296
}
297+
int priority = description().get_node_priority(src_idx, block_round);
298+
if (priority < 0) {
299+
VLOG(VALIDATOR_SESSION_WARNING) << this << "[node " << src << "][broadcast " << sha256_bits256(data.as_slice())
300+
<< "]: node is not a producer in round " << block_round;
301+
return;
302+
}
297303
if (block_round > cur_round_) {
298304
OptimisticBroadcast &optimistic_broadcast = optimistic_broadcasts_[{block_round, src_idx}];
299305
optimistic_broadcast.candidate = std::move(candidate);
300306
optimistic_broadcast.prev_candidate_id = optimistic_prev_candidate;
301307
optimistic_broadcast.broadcast_info = broadcast_info;
302308
VLOG(VALIDATOR_SESSION_WARNING) << this << ": received optimistic broadcast " << block_id << " from " << src
303309
<< ", round " << block_round;
310+
validate_optimistic_broadcast(
311+
BlockSourceInfo{description().get_source_public_key(src_idx),
312+
BlockCandidatePriority{block_round, block_round, priority}},
313+
optimistic_broadcast.candidate->root_hash_, optimistic_broadcast.candidate->data_.clone(),
314+
optimistic_broadcast.candidate->collated_data_.clone(), optimistic_broadcast.prev_candidate_id);
304315
return;
305316
}
306317
if (SentBlock::get_block_id(real_state_->get_committed_block(description(), block_round - 1)) !=
@@ -387,6 +398,37 @@ void ValidatorSessionImpl::process_received_block(td::uint32 block_round, Public
387398
}
388399
}
389400

401+
void ValidatorSessionImpl::validate_optimistic_broadcast(BlockSourceInfo source_info,
402+
ValidatorSessionRootHash root_hash, td::BufferSlice data,
403+
td::BufferSlice collated_data,
404+
ValidatorSessionCandidateId prev_candidate_id) {
405+
if (source_info.priority.round <= cur_round_) {
406+
VLOG(VALIDATOR_SESSION_DEBUG) << this << ": validate optimistic broadcast from "
407+
<< source_info.source.compute_short_id() << " : too old";
408+
return;
409+
}
410+
auto it = blocks_.find(prev_candidate_id);
411+
if (it == blocks_.end()) {
412+
VLOG(VALIDATOR_SESSION_DEBUG) << this << ": validate optimistic broadcast from "
413+
<< source_info.source.compute_short_id() << " : wait for prev block";
414+
block_waiters_[prev_candidate_id].push_back(
415+
[=, SelfId = actor_id(this), data = std::move(data),
416+
collated_data = std::move(collated_data)](td::Result<td::Unit> R) mutable {
417+
if (R.is_ok()) {
418+
td::actor::send_closure(SelfId, &ValidatorSessionImpl::validate_optimistic_broadcast, source_info,
419+
root_hash, std::move(data), std::move(collated_data), prev_candidate_id);
420+
}
421+
});
422+
return;
423+
}
424+
VLOG(VALIDATOR_SESSION_DEBUG) << this << ": validate optimistic broadcast from "
425+
<< source_info.source.compute_short_id();
426+
callback_->on_optimistic_candidate(
427+
source_info, root_hash, std::move(data), std::move(collated_data),
428+
description().get_source_public_key(description().get_source_idx(PublicKeyHash{it->second->src_})),
429+
it->second->root_hash_, it->second->data_.clone(), it->second->collated_data_.clone());
430+
}
431+
390432
void ValidatorSessionImpl::process_message(PublicKeyHash src, td::BufferSlice data) {
391433
}
392434

validator-session/validator-session.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,14 @@ class ValidatorSession : public td::actor::Actor {
9393
ValidatorSessionFileHash file_hash,
9494
ValidatorSessionCollatedDataFileHash collated_data_file_hash,
9595
td::Promise<BlockCandidate> promise) = 0;
96-
virtual void generate_block_optimistic(BlockSourceInfo source_info, td::BufferSlice prev_block, RootHash prev_root_hash,
97-
FileHash prev_file_hash, td::Promise<GeneratedCandidate> promise) {
96+
virtual void generate_block_optimistic(BlockSourceInfo source_info, td::BufferSlice prev_block,
97+
RootHash prev_root_hash, FileHash prev_file_hash,
98+
td::Promise<GeneratedCandidate> promise) {
99+
}
100+
virtual void on_optimistic_candidate(BlockSourceInfo source_info, ValidatorSessionRootHash root_hash,
101+
td::BufferSlice data, td::BufferSlice collated_data, PublicKey prev_source,
102+
ValidatorSessionRootHash prev_root_hash, td::BufferSlice prev_data,
103+
td::BufferSlice prev_collated_data) {
98104
}
99105
virtual ~Callback() = default;
100106
};

validator-session/validator-session.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ class ValidatorSessionImpl : public ValidatorSession {
238238
void process_received_block(td::uint32 block_round, PublicKeyHash src, td::uint32 src_idx,
239239
tl_object_ptr<ton_api::validatorSession_candidate> candidate, const BroadcastInfo &info,
240240
bool is_overlay_broadcast, bool is_startup);
241+
void validate_optimistic_broadcast(BlockSourceInfo source_info, ValidatorSessionRootHash root_hash,
242+
td::BufferSlice data, td::BufferSlice collated_data,
243+
ValidatorSessionCandidateId prev_candidate_id);
241244
void process_message(PublicKeyHash src, td::BufferSlice data);
242245
void process_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
243246

validator/fabric.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,17 @@ struct CollateParams {
4242
Ref<BlockData> optimistic_prev_block = {};
4343
};
4444

45-
enum ValidateMode { fake = 1 };
45+
struct ValidateParams {
46+
ShardIdFull shard;
47+
BlockIdExt min_masterchain_block_id;
48+
std::vector<BlockIdExt> prev;
49+
td::Ref<ValidatorSet> validator_set = {};
50+
PublicKeyHash local_validator_id = PublicKeyHash::zero();;
51+
bool is_fake = false;
52+
53+
// Optional - used for validation of optimistic candidates
54+
Ref<BlockData> optimistic_prev_block = {};
55+
};
4656

4757
td::actor::ActorOwn<Db> create_db_actor(td::actor::ActorId<ValidatorManager> manager, std::string db_root_,
4858
td::Ref<ValidatorManagerOptions> opts);
@@ -96,10 +106,8 @@ void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::Actor
96106
td::Ref<ProofLink> rel_key_block_proof, bool skip_check_signatures = false);
97107
void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::actor::ActorId<ValidatorManager> manager,
98108
td::Timestamp timeout, td::Promise<BlockHandle> promise);
99-
void run_validate_query(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
100-
BlockCandidate candidate, td::Ref<ValidatorSet> validator_set, PublicKeyHash local_validator_id,
101-
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
102-
td::Promise<ValidateCandidateResult> promise, unsigned mode = 0);
109+
void run_validate_query(BlockCandidate candidate, ValidateParams params, td::actor::ActorId<ValidatorManager> manager,
110+
td::Timestamp timeout, td::Promise<ValidateCandidateResult> promise);
103111
void run_collate_query(CollateParams params, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
104112
td::CancellationToken cancellation_token, td::Promise<BlockCandidate> promise);
105113
void run_liteserver_query(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager,

validator/impl/fabric.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,19 @@ void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::act
192192
.release();
193193
}
194194

195-
void run_validate_query(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
196-
BlockCandidate candidate, td::Ref<ValidatorSet> validator_set, PublicKeyHash local_validator_id,
197-
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
198-
td::Promise<ValidateCandidateResult> promise, unsigned mode) {
195+
void run_validate_query(BlockCandidate candidate, ValidateParams params, td::actor::ActorId<ValidatorManager> manager,
196+
td::Timestamp timeout, td::Promise<ValidateCandidateResult> promise) {
199197
BlockSeqno seqno = 0;
200-
for (auto& p : prev) {
198+
for (auto& p : params.prev) {
201199
if (p.seqno() > seqno) {
202200
seqno = p.seqno();
203201
}
204202
}
205-
bool is_fake = mode & ValidateMode::fake;
206203
static std::atomic<size_t> idx;
207-
td::actor::create_actor<ValidateQuery>(PSTRING() << (is_fake ? "fakevalidate" : "validateblock") << shard.to_str()
208-
<< ":" << (seqno + 1) << "#" << idx.fetch_add(1),
209-
shard, min_masterchain_block_id, std::move(prev), std::move(candidate),
210-
std::move(validator_set), local_validator_id, std::move(manager), timeout,
211-
std::move(promise), mode)
204+
td::actor::create_actor<ValidateQuery>(
205+
PSTRING() << (params.is_fake ? "fakevalidate" : "validateblock") << params.shard.to_str() << ":" << (seqno + 1)
206+
<< "#" << idx.fetch_add(1),
207+
std::move(candidate), std::move(params), std::move(manager), timeout, std::move(promise))
212208
.release();
213209
}
214210

validator/impl/validate-query.cpp

Lines changed: 121 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -59,33 +59,29 @@ std::string ErrorCtx::as_string() const {
5959
/**
6060
* Constructs a ValidateQuery object.
6161
*
62-
* @param shard The shard of the block being validated.
63-
* @param min_masterchain_block_id The minimum allowed masterchain block reference for the block.
64-
* @param prev A vector of BlockIdExt representing the previous blocks.
6562
* @param candidate The BlockCandidate to be validated.
66-
* @param validator_set A reference to the ValidatorSet.
63+
* @param params Validation parameters
6764
* @param manager The ActorId of the ValidatorManager.
6865
* @param timeout The timeout for the validation.
6966
* @param promise The Promise to return the ValidateCandidateResult to.
70-
* @param mode +1 - fake mode
7167
*/
72-
ValidateQuery::ValidateQuery(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
73-
BlockCandidate candidate, Ref<ValidatorSet> validator_set,
74-
PublicKeyHash local_validator_id, td::actor::ActorId<ValidatorManager> manager,
75-
td::Timestamp timeout, td::Promise<ValidateCandidateResult> promise, unsigned mode)
76-
: shard_(shard)
68+
ValidateQuery::ValidateQuery(BlockCandidate candidate, ValidateParams params,
69+
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
70+
td::Promise<ValidateCandidateResult> promise)
71+
: shard_(params.shard)
7772
, id_(candidate.id)
78-
, min_mc_block_id(min_masterchain_block_id)
79-
, prev_blocks(std::move(prev))
73+
, min_mc_block_id(params.min_masterchain_block_id)
74+
, prev_blocks(std::move(params.prev))
8075
, block_candidate(std::move(candidate))
81-
, validator_set_(std::move(validator_set))
82-
, local_validator_id_(local_validator_id)
76+
, validator_set_(std::move(params.validator_set))
77+
, local_validator_id_(params.local_validator_id)
8378
, manager(manager)
8479
, timeout(timeout)
8580
, main_promise(std::move(promise))
86-
, is_fake_(mode & ValidateMode::fake)
81+
, is_fake_(params.is_fake)
8782
, shard_pfx_(shard_.shard)
8883
, shard_pfx_len_(ton::shard_prefix_length(shard_))
84+
, optimistic_prev_block_(std::move(params.optimistic_prev_block))
8985
, perf_timer_("validateblock", 0.1, [manager](double duration) {
9086
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "validateblock", duration);
9187
}) {
@@ -350,6 +346,21 @@ void ValidateQuery::start_up() {
350346
// return;
351347
}
352348
}
349+
if (optimistic_prev_block_.not_null()) {
350+
if (is_masterchain()) {
351+
fatal_error("optimistic validation in masterchain is not supported");
352+
return;
353+
}
354+
if (prev_blocks.size() != 1) {
355+
fatal_error("optimistic prev block is not null, which is not allowed after merge");
356+
return;
357+
}
358+
if (prev_blocks[0] != optimistic_prev_block_->block_id()) {
359+
fatal_error("optimistic prev block is not null, but has invalid block id");
360+
return;
361+
}
362+
LOG(WARNING) << "Optimistic prev block id = " << optimistic_prev_block_->block_id().to_str();
363+
}
353364
// 2. learn latest masterchain state and block id
354365
LOG(DEBUG) << "sending get_top_masterchain_state_block() to Manager";
355366
++pending;
@@ -366,17 +377,13 @@ void ValidateQuery::start_up() {
366377
}
367378
// 4. load state(s) corresponding to previous block(s) (not full-collated-data or masterchain)
368379
prev_states.resize(prev_blocks.size());
369-
if (is_masterchain() || !full_collated_data_) {
370-
for (int i = 0; (unsigned)i < prev_blocks.size(); i++) {
371-
// 4.1. load state
372-
LOG(DEBUG) << "sending wait_block_state() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager";
373-
++pending;
374-
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, prev_blocks[i], priority(),
375-
timeout, false, [self = get_self(), i](td::Result<Ref<ShardState>> res) -> void {
376-
LOG(DEBUG) << "got answer to wait_block_state_short query #" << i;
377-
td::actor::send_closure_later(
378-
std::move(self), &ValidateQuery::after_get_shard_state, i, std::move(res));
379-
});
380+
if (is_masterchain() || !full_collated_data_) {
381+
if (optimistic_prev_block_.is_null()) {
382+
load_prev_states();
383+
} else {
384+
if (!process_optimistic_prev_block()) {
385+
return;
386+
}
380387
}
381388
}
382389
// 4. request masterchain handle and state referred to in the block
@@ -409,6 +416,84 @@ void ValidateQuery::start_up() {
409416
CHECK(pending);
410417
}
411418

419+
/**
420+
* Load previous states from DB
421+
*/
422+
void ValidateQuery::load_prev_states() {
423+
for (int i = 0; (unsigned)i < prev_blocks.size(); i++) {
424+
// 4.1. load state
425+
LOG(DEBUG) << "sending wait_block_state() query #" << i << " for " << prev_blocks[i].to_str() << " to Manager";
426+
++pending;
427+
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, prev_blocks[i], priority(),
428+
timeout, false, [self = get_self(), i](td::Result<Ref<ShardState>> res) -> void {
429+
LOG(DEBUG) << "got answer to wait_block_state_short query #" << i;
430+
td::actor::send_closure_later(
431+
std::move(self), &ValidateQuery::after_get_shard_state, i, std::move(res));
432+
});
433+
}
434+
}
435+
436+
/**
437+
* Load previous state for optimistic prev block to apply Merkle update to it
438+
*/
439+
bool ValidateQuery::process_optimistic_prev_block() {
440+
std::vector<BlockIdExt> prev_prev;
441+
BlockIdExt mc_blkid;
442+
bool after_split;
443+
auto S = block::unpack_block_prev_blk_try(optimistic_prev_block_->root_cell(), optimistic_prev_block_->block_id(),
444+
prev_prev, mc_blkid, after_split);
445+
if (S.is_error()) {
446+
return fatal_error(S.move_as_error_prefix("failed to unpack optimistic prev block: "));
447+
}
448+
// 4.1. load state
449+
if (prev_prev.size() == 1) {
450+
LOG(DEBUG) << "sending wait_block_state() query for " << prev_prev[0].to_str() << " to Manager (opt)";
451+
++pending;
452+
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, prev_prev[0], priority(), timeout,
453+
false, [self = get_self()](td::Result<Ref<ShardState>> res) mutable {
454+
LOG(DEBUG) << "got answer to wait_block_state query (opt)";
455+
td::actor::send_closure_later(std::move(self),
456+
&ValidateQuery::after_get_shard_state_optimistic,
457+
std::move(res));
458+
});
459+
} else {
460+
CHECK(prev_prev.size() == 2);
461+
LOG(DEBUG) << "sending wait_block_state_merge() query for " << prev_prev[0].to_str() << " and "
462+
<< prev_prev[1].to_str() << " to Manager (opt)";
463+
++pending;
464+
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_merge, prev_prev[0], prev_prev[1],
465+
priority(), timeout, [self = get_self()](td::Result<Ref<ShardState>> res) mutable {
466+
LOG(DEBUG) << "got answer to wait_block_state_merge query (opt)";
467+
td::actor::send_closure_later(std::move(self),
468+
&ValidateQuery::after_get_shard_state_optimistic,
469+
std::move(res));
470+
});
471+
}
472+
return true;
473+
}
474+
475+
/**
476+
* Callback function called after retrieving previous state for optimistic prev block
477+
*
478+
* @param res The retrieved state.
479+
*/
480+
void ValidateQuery::after_get_shard_state_optimistic(td::Result<Ref<ShardState>> res) {
481+
LOG(DEBUG) << "in ValidateQuery::after_get_shard_state_optimistic()";
482+
if (res.is_error()) {
483+
fatal_error(res.move_as_error());
484+
return;
485+
}
486+
work_timer_.resume();
487+
auto state = res.move_as_ok();
488+
auto S = state.write().apply_block(optimistic_prev_block_->block_id(), optimistic_prev_block_);
489+
if (S.is_error()) {
490+
fatal_error(S.move_as_error_prefix("apply error: "));
491+
return;
492+
}
493+
work_timer_.pause();
494+
after_get_shard_state(0, std::move(state));
495+
}
496+
412497
/**
413498
* Unpacks and validates a block candidate.
414499
*
@@ -1619,11 +1704,16 @@ bool ValidateQuery::request_neighbor_queues() {
16191704
for (block::McShardDescr& descr : neighbors_) {
16201705
LOG(DEBUG) << "requesting outbound queue of neighbor #" << i << " : " << descr.blk_.to_str();
16211706
++pending;
1622-
send_closure_later(manager, &ValidatorManager::wait_block_message_queue_short, descr.blk_, priority(), timeout,
1623-
[self = get_self(), i](td::Result<Ref<MessageQueue>> res) {
1624-
td::actor::send_closure(std::move(self), &ValidateQuery::got_neighbor_out_queue, i,
1625-
std::move(res));
1626-
});
1707+
if (int prev_idx = prev_block_idx(descr.blk_); prev_idx >= 0) {
1708+
td::actor::send_closure(actor_id(this), &ValidateQuery::got_neighbor_out_queue, i,
1709+
prev_states.at(prev_idx)->message_queue());
1710+
} else {
1711+
send_closure_later(manager, &ValidatorManager::wait_block_message_queue_short, descr.blk_, priority(), timeout,
1712+
[self = get_self(), i](td::Result<Ref<MessageQueue>> res) {
1713+
td::actor::send_closure(std::move(self), &ValidateQuery::got_neighbor_out_queue, i,
1714+
std::move(res));
1715+
});
1716+
}
16271717
++i;
16281718
}
16291719
}

0 commit comments

Comments
 (0)