1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

Merge branch 'testnet' into block-generation

This commit is contained in:
SpyCheese 2023-06-02 13:34:00 +03:00
commit e4e77c16c5
463 changed files with 29976 additions and 2517 deletions

View file

@ -9,6 +9,7 @@ set(VALIDATOR_SESSION_SOURCE
validator-session-description.cpp
validator-session-state.cpp
validator-session.cpp
validator-session-round-attempt-state.cpp
persistent-vector.h
validator-session-description.h
@ -16,7 +17,7 @@ set(VALIDATOR_SESSION_SOURCE
validator-session-state.h
validator-session.h
validator-session.hpp
)
validator-session-round-attempt-state.h)
add_library(validatorsession STATIC ${VALIDATOR_SESSION_SOURCE})

View file

@ -322,7 +322,6 @@ class CntVector : public ValidatorSessionDescription::RootObject {
CHECK(idx < size());
return data_[idx];
}
//const T& at(size_t idx) const;
private:
const td::uint32 data_size_;
@ -546,7 +545,6 @@ class CntVector<bool> : public ValidatorSessionDescription::RootObject {
CHECK(idx < max_size());
return get_bit(data_, idx);
}
//const T& at(size_t idx) const;
private:
const td::uint32 data_size_;
@ -734,10 +732,6 @@ class CntSortedVector : public ValidatorSessionDescription::RootObject {
return CntSortedVector::create(desc, std::move(v));
}
/*static const CntSortedVector* merge(ValidatorSessionDescription& desc, const CntSortedVector* l,
const CntSortedVector* r) {
return merge(desc, l, r, [](T l, T r) { return l; });
}*/
static const CntSortedVector* push(ValidatorSessionDescription& desc, const CntSortedVector* v, T value) {
if (!v) {
return create(desc, std::vector<T>{value});
@ -795,7 +789,6 @@ class CntSortedVector : public ValidatorSessionDescription::RootObject {
CHECK(idx < size());
return data_[idx];
}
//const T& at(size_t idx) const;
private:
const td::uint32 data_size_;

View file

@ -51,13 +51,6 @@ ValidatorSessionDescriptionImpl::ValidatorSessionDescriptionImpl(ValidatorSessio
CHECK(it != rev_sources_.end());
self_idx_ = it->second;
pdata_temp_ptr_ = 0;
pdata_temp_size_ = 1 << 27;
pdata_temp_ = new td::uint8[pdata_temp_size_];
pdata_perm_size_ = 1ull << 27;
pdata_perm_ptr_ = 0;
for (auto &el : cache_) {
Cached v{nullptr};
el.store(v, std::memory_order_relaxed);
@ -167,43 +160,11 @@ void ValidatorSessionDescriptionImpl::update_hash(const RootObject *obj, HashTyp
}
void *ValidatorSessionDescriptionImpl::alloc(size_t size, size_t align, bool temp) {
CHECK(align && !(align & (align - 1))); // align should be a power of 2
auto get_padding = [&](const uint8_t* ptr) {
return (-(size_t)ptr) & (align - 1);
};
if (temp) {
pdata_temp_ptr_ += get_padding(pdata_temp_ + pdata_temp_ptr_);
auto s = pdata_temp_ptr_;
pdata_temp_ptr_ += size;
CHECK(s + size <= pdata_temp_size_);
return static_cast<void *>(pdata_temp_ + s);
} else {
while (true) {
size_t idx = pdata_perm_ptr_ / pdata_perm_size_;
if (idx < pdata_perm_.size()) {
auto ptr = pdata_perm_[idx] + (pdata_perm_ptr_ % pdata_perm_size_);
pdata_perm_ptr_ += get_padding(ptr);
ptr += get_padding(ptr);
pdata_perm_ptr_ += size;
if (pdata_perm_ptr_ <= pdata_perm_.size() * pdata_perm_size_) {
return static_cast<void *>(ptr);
}
}
pdata_perm_.push_back(new td::uint8[pdata_perm_size_]);
}
}
return (temp ? mem_temp_ : mem_perm_).alloc(size, align);
}
bool ValidatorSessionDescriptionImpl::is_persistent(const void *ptr) const {
if (ptr == nullptr) {
return true;
}
for (auto &v : pdata_perm_) {
if (ptr >= v && ptr <= v + pdata_perm_size_) {
return true;
}
}
return false;
return mem_perm_.contains(ptr);
}
std::unique_ptr<ValidatorSessionDescription> ValidatorSessionDescription::create(
@ -211,6 +172,58 @@ std::unique_ptr<ValidatorSessionDescription> ValidatorSessionDescription::create
return std::make_unique<ValidatorSessionDescriptionImpl>(std::move(opts), nodes, local_id);
}
ValidatorSessionDescriptionImpl::MemPool::MemPool(size_t chunk_size) : chunk_size_(chunk_size) {
}
ValidatorSessionDescriptionImpl::MemPool::~MemPool() {
for (auto &v : data_) {
delete[] v;
}
}
void *ValidatorSessionDescriptionImpl::MemPool::alloc(size_t size, size_t align) {
CHECK(align && !(align & (align - 1))); // align should be a power of 2
CHECK(size + align <= chunk_size_);
auto get_padding = [&](const uint8_t* ptr) {
return (-(size_t)ptr) & (align - 1);
};
while (true) {
size_t idx = ptr_ / chunk_size_;
if (idx < data_.size()) {
auto ptr = data_[idx] + (ptr_ % chunk_size_);
ptr_ += get_padding(ptr);
ptr += get_padding(ptr);
ptr_ += size;
if (ptr_ <= data_.size() * chunk_size_) {
return static_cast<void *>(ptr);
} else {
ptr_ = data_.size() * chunk_size_;
}
}
data_.push_back(new td::uint8[chunk_size_]);
}
}
void ValidatorSessionDescriptionImpl::MemPool::clear() {
while (data_.size() > 1) {
delete[] data_.back();
data_.pop_back();
}
ptr_ = 0;
}
bool ValidatorSessionDescriptionImpl::MemPool::contains(const void* ptr) const {
if (ptr == nullptr) {
return true;
}
for (auto &v : data_) {
if (ptr >= v && ptr <= v + chunk_size_) {
return true;
}
}
return false;
}
} // namespace validatorsession
} // namespace ton

View file

@ -50,20 +50,30 @@ class ValidatorSessionDescriptionImpl : public ValidatorSessionDescription {
td::uint32 self_idx_;
static constexpr td::uint32 cache_size = (1 << 20);
static constexpr size_t mem_chunk_size_perm = (1 << 27);
static constexpr size_t mem_chunk_size_temp = (1 << 27);
struct Cached {
const RootObject *ptr;
};
std::array<std::atomic<Cached>, cache_size> cache_;
//std::array<std::atomic<Cached>, cache_size> temp_cache_;
td::uint8 *pdata_temp_;
size_t pdata_temp_ptr_;
size_t pdata_temp_size_;
class MemPool {
public:
explicit MemPool(size_t chunk_size);
~MemPool();
void *alloc(size_t size, size_t align);
void clear();
bool contains(const void* ptr) const;
private:
size_t chunk_size_;
std::vector<td::uint8 *> data_;
size_t ptr_ = 0;
};
MemPool mem_perm_ = MemPool(mem_chunk_size_perm);
MemPool mem_temp_ = MemPool(mem_chunk_size_temp);
size_t pdata_perm_size_;
std::vector<td::uint8 *> pdata_perm_;
size_t pdata_perm_ptr_;
std::atomic<td::uint64> reuse_{0};
public:
@ -117,7 +127,7 @@ class ValidatorSessionDescriptionImpl : public ValidatorSessionDescription {
void update_hash(const RootObject *obj, HashType hash) override;
void *alloc(size_t size, size_t align, bool temp) override;
void clear_temp_memory() override {
pdata_temp_ptr_ = 0;
mem_temp_.clear();
}
bool is_persistent(const void *ptr) const override;
HashType compute_hash(td::Slice data) const override;
@ -153,12 +163,6 @@ class ValidatorSessionDescriptionImpl : public ValidatorSessionDescription {
const ValidatorSessionOptions &opts() const override {
return opts_;
}
~ValidatorSessionDescriptionImpl() {
delete[] pdata_temp_;
for (auto &x : pdata_perm_) {
delete[] x;
}
}
};
} // namespace validatorsession

View file

@ -0,0 +1,486 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2020 Telegram Systems LLP
*/
#include "validator-session-state.h"
#include "td/utils/Random.h"
#include "auto/tl/ton_api.hpp"
#include <set>
namespace ton {
namespace validatorsession {
static const SessionVoteCandidate* get_candidate(const VoteVector* vec, ValidatorSessionCandidateId id) {
if (!vec) {
return nullptr;
}
auto size = vec->size();
auto v = vec->data();
for (td::uint32 i = 0; i < size; i++) {
if (v[i]->get_id() == id) {
return v[i];
}
}
return nullptr;
}
//
//
// SessionBlockCandidateSignature
//
//
const SessionBlockCandidateSignature* SessionBlockCandidateSignature::merge(ValidatorSessionDescription& desc,
const SessionBlockCandidateSignature* l,
const SessionBlockCandidateSignature* r) {
if (!l) {
return r;
}
if (!r) {
return l;
}
if (l == r) {
return l;
}
if (l->as_slice() < r->as_slice()) {
return l;
} else {
return r;
}
}
//
//
// SessionBlockCandidate
//
//
bool SessionBlockCandidate::check_block_is_approved(ValidatorSessionDescription& desc) const {
ValidatorWeight w = 0;
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
if (approved_by_->at(i)) {
w += desc.get_node_weight(i);
if (w >= desc.get_cutoff_weight()) {
return true;
}
}
}
return false;
}
const SessionBlockCandidate* SessionBlockCandidate::merge(ValidatorSessionDescription& desc,
const SessionBlockCandidate* l,
const SessionBlockCandidate* r) {
if (!l) {
return r;
}
if (!r) {
return l;
}
if (l == r) {
return l;
}
CHECK(l->get_id() == r->get_id());
auto v = SessionBlockCandidateSignatureVector::merge(
desc, l->approved_by_, r->approved_by_,
[&](const SessionBlockCandidateSignature* l, const SessionBlockCandidateSignature* r) {
return SessionBlockCandidateSignature::merge(desc, l, r);
});
return SessionBlockCandidate::create(desc, l->block_, std::move(v));
}
//
//
// SessionVoteCandidate
//
//
bool SessionVoteCandidate::check_block_is_voted(ValidatorSessionDescription& desc) const {
ValidatorWeight w = 0;
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
if (voted_by_->at(i)) {
w += desc.get_node_weight(i);
if (w >= desc.get_cutoff_weight()) {
return true;
}
}
}
return false;
}
const SessionVoteCandidate* SessionVoteCandidate::merge(ValidatorSessionDescription& desc,
const SessionVoteCandidate* l, const SessionVoteCandidate* r) {
if (!l) {
return r;
}
if (!r) {
return l;
}
if (l == r) {
return l;
}
CHECK(l->get_id() == r->get_id());
auto v = CntVector<bool>::merge(desc, l->voted_by_, r->voted_by_);
return SessionVoteCandidate::create(desc, l->block_, std::move(v));
}
//
//
// ATTEMPT STATE
//
//
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::merge(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* left,
const ValidatorSessionRoundAttemptState* right) {
if (!left) {
return right;
}
if (!right) {
return left;
}
if (left == right) {
return left;
}
CHECK(left->seqno_ == right->seqno_);
const SentBlock* vote_for = nullptr;
bool vote_for_inited = false;
if (!left->vote_for_inited_) {
vote_for = right->vote_for_;
vote_for_inited = right->vote_for_inited_;
} else if (!right->vote_for_inited_) {
vote_for = left->vote_for_;
vote_for_inited = left->vote_for_inited_;
} else if (left->vote_for_ == right->vote_for_) {
vote_for_inited = true;
vote_for = left->vote_for_;
} else {
auto l = SentBlock::get_block_id(left->vote_for_);
auto r = SentBlock::get_block_id(right->vote_for_);
vote_for_inited = true;
if (l < r) {
vote_for = left->vote_for_;
} else {
vote_for = right->vote_for_;
}
}
auto precommitted = CntVector<bool>::merge(desc, left->precommitted_, right->precommitted_);
auto votes = VoteVector::merge(desc, left->votes_, right->votes_,
[&](const SessionVoteCandidate* l, const SessionVoteCandidate* r) {
return SessionVoteCandidate::merge(desc, l, r);
});
return ValidatorSessionRoundAttemptState::create(desc, left->seqno_, std::move(votes), std::move(precommitted),
vote_for, vote_for_inited);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_message_voteFor& act, const ValidatorSessionRoundState* round) {
if (state->vote_for_inited_) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: duplicate VOTEFOR";
return state;
}
if (src_idx != desc.get_vote_for_author(att)) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: bad VOTEFOR author";
return state;
}
if (round->get_first_attempt(src_idx) == 0 && desc.opts().max_round_attempts > 0) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: too early for VOTEFOR";
return state;
}
if (round->get_first_attempt(src_idx) + desc.opts().max_round_attempts > att && desc.opts().max_round_attempts > 0) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: too early for VOTEFOR";
return state;
}
auto x = round->get_block(act.candidate_);
if (!x) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: VOTEFOR for not submitted block";
return state;
}
if (!x->check_block_is_approved(desc)) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: VOTEFOR for not approved block";
return state;
}
return ValidatorSessionRoundAttemptState::create(desc, state->seqno_, state->votes_, state->precommitted_,
x->get_block(), true);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_message_vote& act, const ValidatorSessionRoundState* round) {
bool made;
return make_one(desc, state, src_idx, att, round, &act, made);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_message_precommit& act, const ValidatorSessionRoundState* round) {
bool made;
return make_one(desc, state, src_idx, att, round, &act, made);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_message_empty& act, const ValidatorSessionRoundState* round) {
bool made;
return make_one(desc, state, src_idx, att, round, &act, made);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::try_vote(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ValidatorSessionRoundState* round, const ton_api::validatorSession_round_Message* act,
bool& made) {
made = false;
if (state->check_vote_received_from(src_idx)) {
return state;
}
auto found = false;
auto block = round->choose_block_to_vote(desc, src_idx, att, state->vote_for_, state->vote_for_inited_, found);
if (!found) {
return state;
}
auto block_id = SentBlock::get_block_id(block);
made = true;
if (act) {
if (act->get_id() != ton_api::validatorSession_message_vote::ID) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: expected VOTE(" << block_id << ")";
} else {
auto x = static_cast<const ton_api::validatorSession_message_vote*>(act);
if (x->candidate_ != block_id) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: expected VOTE(" << block_id << ")";
}
}
} else {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx)
<< "]: making implicit VOTE(" << block_id << ")";
}
auto candidate = get_candidate(state->votes_, block_id);
if (!candidate) {
candidate = SessionVoteCandidate::create(desc, block);
}
candidate = SessionVoteCandidate::push(desc, candidate, src_idx);
auto v = VoteVector::push(desc, state->votes_, candidate);
return ValidatorSessionRoundAttemptState::create(desc, state->seqno_, std::move(v), state->precommitted_,
state->vote_for_, state->vote_for_inited_);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::try_precommit(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ValidatorSessionRoundState* round, const ton_api::validatorSession_round_Message* act,
bool& made) {
made = false;
if (state->check_precommit_received_from(src_idx)) {
return state;
}
bool found;
auto block = state->get_voted_block(desc, found);
if (!found) {
return state;
}
made = true;
auto block_id = SentBlock::get_block_id(block);
if (act) {
if (act->get_id() != ton_api::validatorSession_message_precommit::ID) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: expected PRECOMMIT(" << block_id << ")";
} else {
auto x = static_cast<const ton_api::validatorSession_message_precommit*>(act);
if (x->candidate_ != block_id) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: expected PRECOMMIT(" << block_id << ")";
}
}
} else {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx)
<< "]: making implicit PRECOMMIT(" << block_id << ")";
}
auto v = CntVector<bool>::change(desc, state->precommitted_, src_idx, true);
return ValidatorSessionRoundAttemptState::create(desc, state->seqno_, state->votes_, std::move(v), state->vote_for_,
state->vote_for_inited_);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::make_one(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ValidatorSessionRoundState* round, const ton_api::validatorSession_round_Message* act,
bool& made) {
made = false;
state = try_vote(desc, state, src_idx, att, round, act, made);
if (made) {
return state;
}
state = try_precommit(desc, state, src_idx, att, round, act, made);
if (made) {
return state;
}
if (act && act->get_id() != ton_api::validatorSession_message_empty::ID) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: expected EMPTY";
}
return state;
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_round_Message* act, const ValidatorSessionRoundState* round) {
ton_api::downcast_call(*const_cast<ton_api::validatorSession_round_Message*>(act),
[&](auto& obj) { state = action(desc, state, src_idx, att, obj, round); });
return state;
}
bool ValidatorSessionRoundAttemptState::check_vote_received_from(td::uint32 src_idx) const {
if (!votes_) {
return false;
}
auto size = votes_->size();
auto v = votes_->data();
for (td::uint32 i = 0; i < size; i++) {
if (v[i]->check_block_is_voted_by(src_idx)) {
return true;
}
}
return false;
}
bool ValidatorSessionRoundAttemptState::check_precommit_received_from(td::uint32 src_idx) const {
return precommitted_->at(src_idx);
}
const SentBlock* ValidatorSessionRoundAttemptState::get_voted_block(ValidatorSessionDescription& desc, bool& f) const {
f = false;
if (!votes_) {
return nullptr;
}
auto size = votes_->size();
auto v = votes_->data();
for (td::uint32 i = 0; i < size; i++) {
if (v[i]->check_block_is_voted(desc)) {
f = true;
return v[i]->get_block();
}
}
return nullptr;
}
bool ValidatorSessionRoundAttemptState::check_attempt_is_precommitted(ValidatorSessionDescription& desc) const {
ValidatorWeight weight = 0;
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
if (precommitted_->at(i)) {
weight += desc.get_node_weight(i);
if (weight >= desc.get_cutoff_weight()) {
return true;
}
}
}
return false;
}
tl_object_ptr<ton_api::validatorSession_round_Message> ValidatorSessionRoundAttemptState::create_action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundState* round, td::uint32 src_idx,
td::uint32 att) const {
if (!check_vote_received_from(src_idx)) {
auto found = false;
auto B = round->choose_block_to_vote(desc, src_idx, att, vote_for_, vote_for_inited_, found);
if (found) {
auto block_id = SentBlock::get_block_id(B);
return create_tl_object<ton_api::validatorSession_message_vote>(round->get_seqno(), seqno_, block_id);
}
}
if (!check_precommit_received_from(src_idx)) {
bool f = false;
auto B = get_voted_block(desc, f);
if (f) {
auto block_id = SentBlock::get_block_id(B);
return create_tl_object<ton_api::validatorSession_message_precommit>(round->get_seqno(), seqno_, block_id);
}
}
return create_tl_object<ton_api::validatorSession_message_empty>(round->get_seqno(), seqno_);
}
void ValidatorSessionRoundAttemptState::dump(ValidatorSessionDescription& desc, td::StringBuilder& sb) const {
sb << "attempt=" << seqno_ << "\n";
sb << ">>>>\n";
if (vote_for_inited_) {
sb << "vote_for=" << (vote_for_ ? vote_for_->get_src_idx() : std::numeric_limits<td::uint32>::max()) << "\n";
} else {
sb << "vote_for=NONE\n";
}
if (votes_) {
auto s = votes_->size();
sb << "votes: ";
std::vector<td::int32> R;
R.resize(desc.get_total_nodes(), -1);
for (td::uint32 i = 0; i < s; i++) {
const auto e = votes_->at(i);
const auto& x = e->get_voters_list();
for (td::uint32 j = 0; j < desc.get_total_nodes(); j++) {
if (x->at(j)) {
R[j] = e->get_src_idx();
}
}
}
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
sb << R[i] << " ";
}
sb << "\n";
} else {
sb << "votes: EMPTY\n";
}
sb << "precommits: ";
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
const auto e = precommitted_->at(i);
if (e) {
sb << "+ ";
} else {
sb << "- ";
}
}
sb << "\n";
sb << "<<<<\n";
}
} // namespace validatorsession
} // namespace ton

View file

@ -0,0 +1,620 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "td/utils/int_types.h"
#include "td/utils/buffer.h"
#include "adnl/utils.hpp"
#include "common/io.hpp"
#include "persistent-vector.h"
#include "validator-session-description.h"
#include "validator-session-types.h"
#include <limits>
namespace ton {
namespace validatorsession {
using HashType = ValidatorSessionDescription::HashType;
struct SessionBlockCandidateSignature : public ValidatorSessionDescription::RootObject {
public:
static auto create_hash(ValidatorSessionDescription& desc, td::Slice data) {
auto obj = create_tl_object<ton_api::hashable_blockSignature>(desc.compute_hash(data));
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* r, td::Slice data, HashType hash) {
if (!r || r->get_size() < sizeof(SessionBlockCandidateSignature)) {
return false;
}
auto R = static_cast<const SessionBlockCandidateSignature*>(r);
return R->hash_ == hash && R->data_.ubegin() == data.ubegin() && R->data_.size() == data.size();
}
static auto lookup(ValidatorSessionDescription& desc, td::Slice data, HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, data, hash)) {
desc.on_reuse();
return static_cast<const SessionBlockCandidateSignature*>(r);
}
return static_cast<const SessionBlockCandidateSignature*>(nullptr);
}
static SessionBlockCandidateSignature* create(ValidatorSessionDescription& desc, td::BufferSlice value) {
auto hash = create_hash(desc, value.as_slice());
auto d = static_cast<td::uint8*>(desc.alloc(value.size(), 8, false));
td::MutableSlice s{d, value.size()};
s.copy_from(value.as_slice());
return new (desc, true) SessionBlockCandidateSignature{desc, s, hash};
}
static const SessionBlockCandidateSignature* move_to_persistent(ValidatorSessionDescription& desc,
const SessionBlockCandidateSignature* b) {
if (desc.is_persistent(b)) {
return b;
}
CHECK(desc.is_persistent(b->data_.ubegin()));
auto r = lookup(desc, b->data_, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) SessionBlockCandidateSignature{desc, b->data_, b->hash_};
}
static const SessionBlockCandidateSignature* merge(ValidatorSessionDescription& desc,
const SessionBlockCandidateSignature* l,
const SessionBlockCandidateSignature* r);
SessionBlockCandidateSignature(ValidatorSessionDescription& desc, td::Slice data, HashType hash)
: RootObject(sizeof(SessionBlockCandidateSignature)), data_{data}, hash_(std::move(hash)) {
desc.update_hash(this, hash_);
}
td::BufferSlice value() const {
return td::BufferSlice{data_};
}
td::Slice as_slice() const {
return data_;
}
auto get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
private:
const td::Slice data_;
const HashType hash_;
};
using SessionBlockCandidateSignatureVector = CntVector<const SessionBlockCandidateSignature*>;
class SentBlock : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, td::uint32 src_idx, ValidatorSessionRootHash root_hash,
ValidatorSessionFileHash file_hash,
ValidatorSessionCollatedDataFileHash collated_data_file_hash) {
auto obj = create_tl_object<ton_api::hashable_sentBlock>(src_idx, get_vs_hash(desc, root_hash),
get_vs_hash(desc, file_hash),
get_vs_hash(desc, collated_data_file_hash));
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* root_object, td::uint32 src_idx, const ValidatorSessionRootHash& root_hash,
const ValidatorSessionFileHash& file_hash,
const ValidatorSessionCollatedDataFileHash& collated_data_file_hash, HashType hash) {
if (!root_object || root_object->get_size() < sizeof(SentBlock)) {
return false;
}
auto obj = static_cast<const SentBlock*>(root_object);
return obj->src_idx_ == src_idx && obj->root_hash_ == root_hash && obj->file_hash_ == file_hash &&
obj->collated_data_file_hash_ == collated_data_file_hash && obj->hash_ == hash;
}
static auto lookup(ValidatorSessionDescription& desc, td::uint32 src_idx, const ValidatorSessionRootHash& root_hash,
const ValidatorSessionFileHash& file_hash,
const ValidatorSessionCollatedDataFileHash& collated_data_file_hash, HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, src_idx, root_hash, file_hash, collated_data_file_hash, hash)) {
desc.on_reuse();
return static_cast<const SentBlock*>(r);
}
return static_cast<const SentBlock*>(nullptr);
}
static const SentBlock* create(ValidatorSessionDescription& desc, td::uint32 src_idx,
const ValidatorSessionRootHash& root_hash, const ValidatorSessionFileHash& file_hash,
const ValidatorSessionCollatedDataFileHash& collated_data_file_hash) {
auto hash = create_hash(desc, src_idx, root_hash, file_hash, collated_data_file_hash);
auto r = lookup(desc, src_idx, root_hash, file_hash, collated_data_file_hash, hash, true);
if (r) {
return r;
}
auto candidate_id = desc.candidate_id(src_idx, root_hash, file_hash, collated_data_file_hash);
return new (desc, true) SentBlock{desc, src_idx, root_hash, file_hash, collated_data_file_hash, candidate_id, hash};
}
static const SentBlock* create(ValidatorSessionDescription& desc, const ValidatorSessionCandidateId& zero) {
CHECK(zero.is_zero());
auto hash = create_hash(desc, 0, ValidatorSessionRootHash::zero(), ValidatorSessionFileHash::zero(),
ValidatorSessionCollatedDataFileHash::zero());
return new (desc, true) SentBlock{desc,
0,
ValidatorSessionRootHash::zero(),
ValidatorSessionFileHash::zero(),
ValidatorSessionCollatedDataFileHash::zero(),
zero,
hash};
}
static const SentBlock* move_to_persistent(ValidatorSessionDescription& desc, const SentBlock* b) {
if (desc.is_persistent(b)) {
return b;
}
auto r = lookup(desc, b->src_idx_, b->root_hash_, b->file_hash_, b->collated_data_file_hash_, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) SentBlock{
desc, b->src_idx_, b->root_hash_, b->file_hash_, b->collated_data_file_hash_, b->candidate_id_, b->hash_};
}
SentBlock(ValidatorSessionDescription& desc, td::uint32 src_idx, ValidatorSessionRootHash root_hash,
ValidatorSessionFileHash file_hash, ValidatorSessionCollatedDataFileHash collated_data_file_hash,
ValidatorSessionCandidateId candidate_id, HashType hash)
: RootObject(sizeof(SentBlock))
, src_idx_(src_idx)
, root_hash_(std::move(root_hash))
, file_hash_(std::move(file_hash))
, collated_data_file_hash_(std::move(collated_data_file_hash))
, candidate_id_(candidate_id)
, hash_(std::move(hash)) {
desc.update_hash(this, hash_);
}
auto get_src_idx() const {
return src_idx_;
}
auto get_root_hash() const {
return root_hash_;
}
auto get_file_hash() const {
return file_hash_;
}
auto get_collated_data_file_hash() const {
return collated_data_file_hash_;
}
static ValidatorSessionCandidateId get_block_id(const SentBlock* block) {
return block ? block->candidate_id_ : skip_round_candidate_id();
}
HashType get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
bool operator<(const SentBlock& block) const {
if (src_idx_ < block.src_idx_) {
return true;
}
if (src_idx_ > block.src_idx_) {
return false;
}
if (candidate_id_ < block.candidate_id_) {
return true;
}
return false;
}
struct Compare {
bool operator()(const SentBlock* a, const SentBlock* b) const {
return *a < *b;
}
};
private:
const td::uint32 src_idx_;
const ValidatorSessionRootHash root_hash_;
const ValidatorSessionFileHash file_hash_;
const ValidatorSessionCollatedDataFileHash collated_data_file_hash_;
const ValidatorSessionCandidateId candidate_id_;
const HashType hash_;
};
class SessionBlockCandidate : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, HashType block, HashType approved) {
auto obj = create_tl_object<ton_api::hashable_blockCandidate>(block, approved);
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* r, const SentBlock* block, const SessionBlockCandidateSignatureVector* approved,
HashType hash) {
if (!r || r->get_size() < sizeof(SessionBlockCandidate)) {
return false;
}
auto R = static_cast<const SessionBlockCandidate*>(r);
return R->block_ == block && R->approved_by_ == approved && R->hash_ == hash;
}
static auto lookup(ValidatorSessionDescription& desc, const SentBlock* block,
const SessionBlockCandidateSignatureVector* approved, HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, block, approved, hash)) {
desc.on_reuse();
return static_cast<const SessionBlockCandidate*>(r);
}
return static_cast<const SessionBlockCandidate*>(nullptr);
}
static const SessionBlockCandidate* create(ValidatorSessionDescription& desc, const SentBlock* block,
const SessionBlockCandidateSignatureVector* approved) {
auto hash = create_hash(desc, get_vs_hash(desc, block), get_vs_hash(desc, approved));
auto r = lookup(desc, block, approved, hash, true);
if (r) {
return r;
}
return new (desc, true) SessionBlockCandidate(desc, block, approved, hash);
}
static const SessionBlockCandidate* create(ValidatorSessionDescription& desc, const SentBlock* block) {
std::vector<const SessionBlockCandidateSignature*> v;
v.resize(desc.get_total_nodes(), nullptr);
auto vec = SessionBlockCandidateSignatureVector::create(desc, std::move(v));
return create(desc, block, vec);
}
static const SessionBlockCandidate* move_to_persistent(ValidatorSessionDescription& desc,
const SessionBlockCandidate* b) {
if (desc.is_persistent(b)) {
return b;
}
auto block = SentBlock::move_to_persistent(desc, b->block_);
auto approved = SessionBlockCandidateSignatureVector::move_to_persistent(desc, b->approved_by_);
auto r = lookup(desc, block, approved, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) SessionBlockCandidate{desc, block, approved, b->hash_};
}
SessionBlockCandidate(ValidatorSessionDescription& desc, const SentBlock* block,
const SessionBlockCandidateSignatureVector* approved, HashType hash)
: RootObject{sizeof(SessionBlockCandidate)}, block_(block), approved_by_(approved), hash_(hash) {
desc.update_hash(this, hash_);
}
static const SessionBlockCandidate* merge(ValidatorSessionDescription& desc, const SessionBlockCandidate* l,
const SessionBlockCandidate* r);
auto get_block() const {
return block_;
}
auto get_id() const {
return SentBlock::get_block_id(block_);
}
auto get_src_idx() const {
return block_ ? block_->get_src_idx() : std::numeric_limits<td::uint32>::max();
}
bool check_block_is_approved_by(td::uint32 src_idx) const {
return approved_by_->at(src_idx);
}
bool check_block_is_approved(ValidatorSessionDescription& desc) const;
auto get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
auto get_approvers_list() const {
return approved_by_;
}
static const SessionBlockCandidate* push(ValidatorSessionDescription& desc, const SessionBlockCandidate* state,
td::uint32 src_idx, const SessionBlockCandidateSignature* sig) {
CHECK(state);
if (state->approved_by_->at(src_idx)) {
return state;
}
return create(desc, state->block_,
SessionBlockCandidateSignatureVector::change(desc, state->approved_by_, src_idx, sig));
}
class Compare {
public:
bool operator()(const SessionBlockCandidate* l, const SessionBlockCandidate* r) {
return l->get_id() < r->get_id();
}
};
private:
const SentBlock* block_;
const SessionBlockCandidateSignatureVector* approved_by_;
const HashType hash_;
};
class SessionVoteCandidate : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, HashType block, HashType voted) {
auto obj = create_tl_object<ton_api::hashable_blockVoteCandidate>(block, voted);
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* r, const SentBlock* block, const CntVector<bool>* voted, HashType hash) {
if (!r || r->get_size() < sizeof(SessionVoteCandidate)) {
return false;
}
auto R = static_cast<const SessionVoteCandidate*>(r);
return R->block_ == block && R->voted_by_ == voted && R->hash_ == hash;
}
static auto lookup(ValidatorSessionDescription& desc, const SentBlock* block, const CntVector<bool>* voted,
HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, block, voted, hash)) {
desc.on_reuse();
return static_cast<const SessionVoteCandidate*>(r);
}
return static_cast<const SessionVoteCandidate*>(nullptr);
}
static const SessionVoteCandidate* create(ValidatorSessionDescription& desc, const SentBlock* block,
const CntVector<bool>* voted) {
auto hash = create_hash(desc, get_vs_hash(desc, block), get_vs_hash(desc, voted));
auto r = lookup(desc, block, voted, hash, true);
if (r) {
return r;
}
return new (desc, true) SessionVoteCandidate(desc, block, voted, hash);
}
static const SessionVoteCandidate* create(ValidatorSessionDescription& desc, const SentBlock* block) {
std::vector<bool> v;
v.resize(desc.get_total_nodes(), false);
auto vec = CntVector<bool>::create(desc, std::move(v));
return create(desc, block, vec);
}
static const SessionVoteCandidate* move_to_persistent(ValidatorSessionDescription& desc,
const SessionVoteCandidate* b) {
if (desc.is_persistent(b)) {
return b;
}
auto block = SentBlock::move_to_persistent(desc, b->block_);
auto voted = CntVector<bool>::move_to_persistent(desc, b->voted_by_);
auto r = lookup(desc, block, voted, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) SessionVoteCandidate{desc, block, voted, b->hash_};
}
SessionVoteCandidate(ValidatorSessionDescription& desc, const SentBlock* block, const CntVector<bool>* voted,
HashType hash)
: RootObject{sizeof(SessionVoteCandidate)}, block_(block), voted_by_(voted), hash_(hash) {
desc.update_hash(this, hash_);
}
static const SessionVoteCandidate* merge(ValidatorSessionDescription& desc, const SessionVoteCandidate* l,
const SessionVoteCandidate* r);
auto get_block() const {
return block_;
}
auto get_id() const {
return SentBlock::get_block_id(block_);
}
auto get_src_idx() const {
return block_ ? block_->get_src_idx() : std::numeric_limits<td::uint32>::max();
}
bool check_block_is_voted_by(td::uint32 src_idx) const {
return voted_by_->at(src_idx);
}
bool check_block_is_voted(ValidatorSessionDescription& desc) const;
auto get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
auto get_voters_list() const {
return voted_by_;
}
static const SessionVoteCandidate* push(ValidatorSessionDescription& desc, const SessionVoteCandidate* state,
td::uint32 src_idx) {
CHECK(state);
if (state->voted_by_->at(src_idx)) {
return state;
}
return create(desc, state->block_, CntVector<bool>::change(desc, state->voted_by_, src_idx, true));
}
class Compare {
public:
bool operator()(const SessionVoteCandidate* l, const SessionVoteCandidate* r) {
return l->get_id() < r->get_id();
}
};
private:
const SentBlock* block_;
const CntVector<bool>* voted_by_;
const HashType hash_;
};
using VoteVector = CntSortedVector<const SessionVoteCandidate*, SessionVoteCandidate::Compare>;
using ApproveVector = CntSortedVector<const SessionBlockCandidate*, SessionBlockCandidate::Compare>;
class ValidatorSessionRoundState;
class ValidatorSessionRoundAttemptState : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, td::uint32 seqno, HashType votes,
HashType precommitted, bool vote_for_inited, HashType vote_for) {
auto obj = create_tl_object<ton_api::hashable_validatorSessionRoundAttempt>(seqno, votes, precommitted,
vote_for_inited, vote_for);
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* r, td::uint32 seqno, const VoteVector* votes,
const CntVector<bool>* precommitted, const SentBlock* vote_for, bool vote_for_inited,
HashType hash) {
if (!r || r->get_size() < sizeof(ValidatorSessionRoundAttemptState)) {
return false;
}
auto R = static_cast<const ValidatorSessionRoundAttemptState*>(r);
return R->seqno_ == seqno && R->votes_ == votes && R->precommitted_ == precommitted && R->vote_for_ == vote_for &&
R->vote_for_inited_ == vote_for_inited && R->hash_ == hash;
}
static auto lookup(ValidatorSessionDescription& desc, td::uint32 seqno, const VoteVector* votes,
const CntVector<bool>* precommitted, const SentBlock* vote_for, bool vote_for_inited,
HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, seqno, votes, precommitted, vote_for, vote_for_inited, hash)) {
desc.on_reuse();
return static_cast<const ValidatorSessionRoundAttemptState*>(r);
}
return static_cast<const ValidatorSessionRoundAttemptState*>(nullptr);
}
static const ValidatorSessionRoundAttemptState* move_to_persistent(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* b) {
if (desc.is_persistent(b)) {
return b;
}
auto votes = VoteVector::move_to_persistent(desc, b->votes_);
auto precommitted = CntVector<bool>::move_to_persistent(desc, b->precommitted_);
auto vote_for = SentBlock::move_to_persistent(desc, b->vote_for_);
auto r = lookup(desc, b->seqno_, votes, precommitted, vote_for, b->vote_for_inited_, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) ValidatorSessionRoundAttemptState{desc, b->seqno_, votes, precommitted,
vote_for, b->vote_for_inited_, b->hash_};
}
static const ValidatorSessionRoundAttemptState* create(ValidatorSessionDescription& desc, td::uint32 seqno,
const VoteVector* votes, const CntVector<bool>* precommitted,
const SentBlock* vote_for, bool vote_for_inited) {
auto hash = create_hash(desc, seqno, get_vs_hash(desc, votes), get_vs_hash(desc, precommitted),
get_vs_hash(desc, vote_for), vote_for_inited);
auto r = lookup(desc, seqno, votes, precommitted, vote_for, vote_for_inited, hash, true);
if (r) {
return r;
}
return new (desc, true)
ValidatorSessionRoundAttemptState(desc, seqno, votes, precommitted, vote_for, vote_for_inited, hash);
}
static const ValidatorSessionRoundAttemptState* create(ValidatorSessionDescription& desc, td::uint32 seqno) {
std::vector<bool> x;
x.resize(desc.get_total_nodes(), false);
auto p = CntVector<bool>::create(desc, std::move(x));
return create(desc, seqno, nullptr, p, nullptr, false);
}
ValidatorSessionRoundAttemptState(ValidatorSessionDescription& desc, td::uint32 seqno, const VoteVector* votes,
const CntVector<bool>* precommitted, const SentBlock* vote_for,
bool vote_for_inited, HashType hash)
: RootObject{sizeof(ValidatorSessionRoundAttemptState)}
, seqno_(seqno)
, votes_(votes)
, precommitted_(precommitted)
, vote_for_(vote_for)
, vote_for_inited_(vote_for_inited)
, hash_(std::move(hash)) {
desc.update_hash(this, hash_);
}
auto get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
auto get_seqno() const {
return seqno_;
}
auto get_votes() const {
return votes_;
}
auto get_precommits() const {
return precommitted_;
}
const SentBlock* get_voted_block(ValidatorSessionDescription& desc, bool& f) const;
const SentBlock* get_vote_for_block(ValidatorSessionDescription& desc, bool& f) const {
f = vote_for_inited_;
return vote_for_;
}
bool check_attempt_is_precommitted(ValidatorSessionDescription& desc) const;
bool check_vote_received_from(td::uint32 src_idx) const;
bool check_precommit_received_from(td::uint32 src_idx) const;
bool operator<(const ValidatorSessionRoundAttemptState& right) const {
return seqno_ < right.seqno_;
}
struct Compare {
bool operator()(const ValidatorSessionRoundAttemptState* a, const ValidatorSessionRoundAttemptState* b) const {
return *a < *b;
}
};
static const ValidatorSessionRoundAttemptState* merge(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* left,
const ValidatorSessionRoundAttemptState* right);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_message_voteFor& act,
const ValidatorSessionRoundState* round);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_message_vote& act,
const ValidatorSessionRoundState* round);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_message_precommit& act,
const ValidatorSessionRoundState* round);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_message_empty& act,
const ValidatorSessionRoundState* round);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_round_Message* action,
const ValidatorSessionRoundState* round);
template <class T>
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att, const T& action,
const ValidatorSessionRoundState* round) {
UNREACHABLE();
}
static const ValidatorSessionRoundAttemptState* try_vote(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ValidatorSessionRoundState* round,
const ton_api::validatorSession_round_Message* cmp,
bool& made);
static const ValidatorSessionRoundAttemptState* try_precommit(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ValidatorSessionRoundState* round,
const ton_api::validatorSession_round_Message* cmp,
bool& made);
static const ValidatorSessionRoundAttemptState* make_one(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ValidatorSessionRoundState* round,
const ton_api::validatorSession_round_Message* cmp,
bool& made);
tl_object_ptr<ton_api::validatorSession_round_Message> create_action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundState* round,
td::uint32 src_idx, td::uint32 att) const;
void dump(ValidatorSessionDescription& desc, td::StringBuilder& sb) const;
private:
const td::uint32 seqno_;
const VoteVector* votes_;
const CntVector<bool>* precommitted_;
const SentBlock* vote_for_;
const bool vote_for_inited_;
const HashType hash_;
};
using AttemptVector =
CntSortedVector<const ValidatorSessionRoundAttemptState*, ValidatorSessionRoundAttemptState::Compare>;
} // namespace validatorsession
} // namespace ton

View file

@ -67,14 +67,6 @@ namespace ton {
namespace validatorsession {
static td::uint32 get_round_id(const ton_api::validatorSession_round_Message* message) {
td::uint32 round = 0;
bool is_called = ton_api::downcast_call(*const_cast<ton_api::validatorSession_round_Message*>(message),
[&](auto& obj) { round = obj.round_; });
CHECK(is_called);
return round;
}
static const ValidatorSessionRoundAttemptState* get_attempt(const AttemptVector* vec, td::uint32 seqno) {
if (!vec) {
return nullptr;
@ -108,118 +100,12 @@ static const SessionBlockCandidate* get_candidate(const ApproveVector* vec, Vali
return nullptr;
}
static const SessionVoteCandidate* get_candidate(const VoteVector* vec, ValidatorSessionCandidateId id) {
if (!vec) {
return nullptr;
}
auto size = vec->size();
auto v = vec->data();
for (td::uint32 i = 0; i < size; i++) {
if (v[i]->get_id() == id) {
return v[i];
}
}
return nullptr;
}
//
//
// SessionBlockCandidateSignature
//
//
const SessionBlockCandidateSignature* SessionBlockCandidateSignature::merge(ValidatorSessionDescription& desc,
const SessionBlockCandidateSignature* l,
const SessionBlockCandidateSignature* r) {
if (!l) {
return r;
}
if (!r) {
return l;
}
if (l == r) {
return l;
}
if (l->as_slice() < r->as_slice()) {
return l;
} else {
return r;
}
}
//
//
// SessionBlockCandidate
//
//
bool SessionBlockCandidate::check_block_is_approved(ValidatorSessionDescription& desc) const {
ValidatorWeight w = 0;
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
if (approved_by_->at(i)) {
w += desc.get_node_weight(i);
if (w >= desc.get_cutoff_weight()) {
return true;
}
}
}
return false;
}
const SessionBlockCandidate* SessionBlockCandidate::merge(ValidatorSessionDescription& desc,
const SessionBlockCandidate* l,
const SessionBlockCandidate* r) {
if (!l) {
return r;
}
if (!r) {
return l;
}
if (l == r) {
return l;
}
CHECK(l->get_id() == r->get_id());
auto v = SessionBlockCandidateSignatureVector::merge(
desc, l->approved_by_, r->approved_by_,
[&](const SessionBlockCandidateSignature* l, const SessionBlockCandidateSignature* r) {
return SessionBlockCandidateSignature::merge(desc, l, r);
});
return SessionBlockCandidate::create(desc, l->block_, std::move(v));
}
//
//
// SessionVoteCandidate
//
//
bool SessionVoteCandidate::check_block_is_voted(ValidatorSessionDescription& desc) const {
ValidatorWeight w = 0;
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
if (voted_by_->at(i)) {
w += desc.get_node_weight(i);
if (w >= desc.get_cutoff_weight()) {
return true;
}
}
}
return false;
}
const SessionVoteCandidate* SessionVoteCandidate::merge(ValidatorSessionDescription& desc,
const SessionVoteCandidate* l, const SessionVoteCandidate* r) {
if (!l) {
return r;
}
if (!r) {
return l;
}
if (l == r) {
return l;
}
CHECK(l->get_id() == r->get_id());
auto v = CntVector<bool>::merge(desc, l->voted_by_, r->voted_by_);
return SessionVoteCandidate::create(desc, l->block_, std::move(v));
static td::uint32 get_round_id(const ton_api::validatorSession_round_Message* message) {
td::uint32 round = 0;
bool is_called = ton_api::downcast_call(*const_cast<ton_api::validatorSession_round_Message*>(message),
[&](auto& obj) { round = obj.round_; });
CHECK(is_called);
return round;
}
//
@ -374,346 +260,6 @@ const ValidatorSessionOldRoundState* ValidatorSessionOldRoundState::action(
return state;
}
//
//
// ATTEMPT STATE
//
//
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::merge(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* left,
const ValidatorSessionRoundAttemptState* right) {
if (!left) {
return right;
}
if (!right) {
return left;
}
if (left == right) {
return left;
}
CHECK(left->seqno_ == right->seqno_);
const SentBlock* vote_for = nullptr;
bool vote_for_inited = false;
if (!left->vote_for_inited_) {
vote_for = right->vote_for_;
vote_for_inited = right->vote_for_inited_;
} else if (!right->vote_for_inited_) {
vote_for = left->vote_for_;
vote_for_inited = left->vote_for_inited_;
} else if (left->vote_for_ == right->vote_for_) {
vote_for_inited = true;
vote_for = left->vote_for_;
} else {
auto l = SentBlock::get_block_id(left->vote_for_);
auto r = SentBlock::get_block_id(right->vote_for_);
vote_for_inited = true;
if (l < r) {
vote_for = left->vote_for_;
} else {
vote_for = right->vote_for_;
}
}
auto precommitted = CntVector<bool>::merge(desc, left->precommitted_, right->precommitted_);
auto votes = VoteVector::merge(desc, left->votes_, right->votes_,
[&](const SessionVoteCandidate* l, const SessionVoteCandidate* r) {
return SessionVoteCandidate::merge(desc, l, r);
});
return ValidatorSessionRoundAttemptState::create(desc, left->seqno_, std::move(votes), std::move(precommitted),
vote_for, vote_for_inited);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_message_voteFor& act, const ValidatorSessionRoundState* round) {
if (state->vote_for_inited_) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: duplicate VOTEFOR";
return state;
}
if (src_idx != desc.get_vote_for_author(att)) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: bad VOTEFOR author";
return state;
}
if (round->get_first_attempt(src_idx) == 0 && desc.opts().max_round_attempts > 0) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: too early for VOTEFOR";
return state;
}
if (round->get_first_attempt(src_idx) + desc.opts().max_round_attempts > att && desc.opts().max_round_attempts == 0) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: too early for VOTEFOR";
return state;
}
auto x = round->get_block(act.candidate_);
if (!x) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: VOTEFOR for not approved block";
return state;
}
if (!x->check_block_is_approved(desc)) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: VOTEFOR for not approved block";
return state;
}
return ValidatorSessionRoundAttemptState::create(desc, state->seqno_, state->votes_, state->precommitted_,
x->get_block(), true);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_message_vote& act, const ValidatorSessionRoundState* round) {
bool made;
return make_one(desc, state, src_idx, att, round, &act, made);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_message_precommit& act, const ValidatorSessionRoundState* round) {
bool made;
return make_one(desc, state, src_idx, att, round, &act, made);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_message_empty& act, const ValidatorSessionRoundState* round) {
bool made;
return make_one(desc, state, src_idx, att, round, &act, made);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::try_vote(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ValidatorSessionRoundState* round, const ton_api::validatorSession_round_Message* act,
bool& made) {
made = false;
if (state->check_vote_received_from(src_idx)) {
return state;
}
auto found = false;
auto block = round->choose_block_to_vote(desc, src_idx, att, state->vote_for_, state->vote_for_inited_, found);
if (!found) {
return state;
}
auto block_id = SentBlock::get_block_id(block);
made = true;
if (act) {
if (act->get_id() != ton_api::validatorSession_message_vote::ID) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: expected VOTE(" << block_id << ")";
} else {
auto x = static_cast<const ton_api::validatorSession_message_vote*>(act);
if (x->candidate_ != block_id) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: expected VOTE(" << block_id << ")";
}
}
} else {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx)
<< "]: making implicit VOTE(" << block_id << ")";
}
auto candidate = get_candidate(state->votes_, block_id);
if (!candidate) {
candidate = SessionVoteCandidate::create(desc, block);
}
candidate = SessionVoteCandidate::push(desc, candidate, src_idx);
auto v = VoteVector::push(desc, state->votes_, candidate);
return ValidatorSessionRoundAttemptState::create(desc, state->seqno_, std::move(v), state->precommitted_,
state->vote_for_, state->vote_for_inited_);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::try_precommit(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ValidatorSessionRoundState* round, const ton_api::validatorSession_round_Message* act,
bool& made) {
made = false;
if (state->check_precommit_received_from(src_idx)) {
return state;
}
bool found;
auto block = state->get_voted_block(desc, found);
if (!found) {
return state;
}
made = true;
auto block_id = SentBlock::get_block_id(block);
if (act) {
if (act->get_id() != ton_api::validatorSession_message_precommit::ID) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: expected PRECOMMIT(" << block_id << ")";
} else {
auto x = static_cast<const ton_api::validatorSession_message_precommit*>(act);
if (x->candidate_ != block_id) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: expected PRECOMMIT(" << block_id << ")";
}
}
} else {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx)
<< "]: making implicit PRECOMMIT(" << block_id << ")";
}
auto v = CntVector<bool>::change(desc, state->precommitted_, src_idx, true);
return ValidatorSessionRoundAttemptState::create(desc, state->seqno_, state->votes_, std::move(v), state->vote_for_,
state->vote_for_inited_);
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::make_one(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ValidatorSessionRoundState* round, const ton_api::validatorSession_round_Message* act,
bool& made) {
made = false;
state = try_vote(desc, state, src_idx, att, round, act, made);
if (made) {
return state;
}
state = try_precommit(desc, state, src_idx, att, round, act, made);
if (made) {
return state;
}
if (act && act->get_id() != ton_api::validatorSession_message_empty::ID) {
VLOG(VALIDATOR_SESSION_WARNING) << "[validator session][node " << desc.get_source_id(src_idx) << "][" << act
<< "]: invalid message: expected EMPTY";
}
return state;
}
const ValidatorSessionRoundAttemptState* ValidatorSessionRoundAttemptState::action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundAttemptState* state, td::uint32 src_idx,
td::uint32 att, const ton_api::validatorSession_round_Message* act, const ValidatorSessionRoundState* round) {
ton_api::downcast_call(*const_cast<ton_api::validatorSession_round_Message*>(act),
[&](auto& obj) { state = action(desc, state, src_idx, att, obj, round); });
return state;
}
bool ValidatorSessionRoundAttemptState::check_vote_received_from(td::uint32 src_idx) const {
if (!votes_) {
return false;
}
auto size = votes_->size();
auto v = votes_->data();
for (td::uint32 i = 0; i < size; i++) {
if (v[i]->check_block_is_voted_by(src_idx)) {
return true;
}
}
return false;
}
bool ValidatorSessionRoundAttemptState::check_precommit_received_from(td::uint32 src_idx) const {
return precommitted_->at(src_idx);
}
const SentBlock* ValidatorSessionRoundAttemptState::get_voted_block(ValidatorSessionDescription& desc, bool& f) const {
f = false;
if (!votes_) {
return nullptr;
}
auto size = votes_->size();
auto v = votes_->data();
for (td::uint32 i = 0; i < size; i++) {
if (v[i]->check_block_is_voted(desc)) {
f = true;
return v[i]->get_block();
}
}
return nullptr;
}
bool ValidatorSessionRoundAttemptState::check_attempt_is_precommitted(ValidatorSessionDescription& desc) const {
ValidatorWeight weight = 0;
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
if (precommitted_->at(i)) {
weight += desc.get_node_weight(i);
if (weight >= desc.get_cutoff_weight()) {
return true;
}
}
}
return false;
}
tl_object_ptr<ton_api::validatorSession_round_Message> ValidatorSessionRoundAttemptState::create_action(
ValidatorSessionDescription& desc, const ValidatorSessionRoundState* round, td::uint32 src_idx,
td::uint32 att) const {
if (!check_vote_received_from(src_idx)) {
auto found = false;
auto B = round->choose_block_to_vote(desc, src_idx, att, vote_for_, vote_for_inited_, found);
if (found) {
auto block_id = SentBlock::get_block_id(B);
return create_tl_object<ton_api::validatorSession_message_vote>(round->get_seqno(), seqno_, block_id);
}
}
if (!check_precommit_received_from(src_idx)) {
bool f = false;
auto B = get_voted_block(desc, f);
if (f) {
auto block_id = SentBlock::get_block_id(B);
return create_tl_object<ton_api::validatorSession_message_precommit>(round->get_seqno(), seqno_, block_id);
}
}
return create_tl_object<ton_api::validatorSession_message_empty>(round->get_seqno(), seqno_);
}
void ValidatorSessionRoundAttemptState::dump(ValidatorSessionDescription& desc, td::StringBuilder& sb) const {
sb << "attempt=" << seqno_ << "\n";
sb << ">>>>\n";
if (vote_for_inited_) {
sb << "vote_for=" << (vote_for_ ? vote_for_->get_src_idx() : std::numeric_limits<td::uint32>::max()) << "\n";
} else {
sb << "vote_for=NONE\n";
}
if (votes_) {
auto s = votes_->size();
sb << "votes: ";
std::vector<td::int32> R;
R.resize(desc.get_total_nodes(), -1);
for (td::uint32 i = 0; i < s; i++) {
const auto e = votes_->at(i);
const auto& x = e->get_voters_list();
for (td::uint32 j = 0; j < desc.get_total_nodes(); j++) {
if (x->at(j)) {
R[j] = e->get_src_idx();
}
}
}
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
sb << R[i] << " ";
}
sb << "\n";
} else {
sb << "votes: EMPTY\n";
}
sb << "precommits: ";
for (td::uint32 i = 0; i < desc.get_total_nodes(); i++) {
const auto e = precommitted_->at(i);
if (e) {
sb << "+ ";
} else {
sb << "- ";
}
}
sb << "\n";
sb << "<<<<\n";
}
//
//
// ROUND STATE
@ -821,8 +367,6 @@ const ValidatorSessionRoundState* ValidatorSessionRoundState::merge(ValidatorSes
return SessionBlockCandidateSignature::merge(desc, l, r);
});
//auto sent_vec = SentBlockVector::merge(desc, left->sent_blocks_, right->sent_blocks_);
auto sent = ApproveVector::merge(desc, left->sent_blocks_, right->sent_blocks_,
[&](const SessionBlockCandidate* l, const SessionBlockCandidate* r) {
return SessionBlockCandidate::merge(desc, l, r);
@ -985,9 +529,6 @@ const ValidatorSessionRoundState* ValidatorSessionRoundState::forward_action_to_
attempt = ValidatorSessionRoundAttemptState::create(desc, att);
}
bool had_voted_block;
attempt->get_voted_block(desc, had_voted_block);
ton_api::downcast_call(*const_cast<ton_api::validatorSession_round_Message*>(act), [&](auto& obj) {
attempt = ValidatorSessionRoundAttemptState::action(desc, attempt, src_idx, att, obj, state);
});
@ -1302,6 +843,8 @@ std::vector<const SentBlock*> ValidatorSessionRoundState::choose_blocks_to_appro
CHECK(prio >= 0);
td::uint32 blk_src_idx = B->get_src_idx();
if (was_source.count(blk_src_idx) > 0) {
// Any honest validator submits at most one block in a round
// Therefore, we can ignore all blocks from a node if it submits more than one
x[prio] = nullptr;
} else {
was_source.insert(blk_src_idx);

View file

@ -24,15 +24,15 @@
#include "common/io.hpp"
#include "persistent-vector.h"
#include "validator-session-description.h"
#include "validator-session-types.h"
#include "validator-session-round-attempt-state.h"
#include <limits>
namespace td {
td::StringBuilder& operator<<(td::StringBuilder& sb, const ton::ton_api::validatorSession_round_Message& message);
td::StringBuilder& operator<<(td::StringBuilder& sb, const ton::ton_api::validatorSession_round_Message* message);
}
@ -41,410 +41,6 @@ namespace ton {
namespace validatorsession {
using HashType = ValidatorSessionDescription::HashType;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_WARNING) = verbosity_WARNING;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_NOTICE) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_INFO) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_DEBUG) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_EXTRA_DEBUG) = verbosity_DEBUG + 1;
struct SessionBlockCandidateSignature : public ValidatorSessionDescription::RootObject {
public:
static auto create_hash(ValidatorSessionDescription& desc, td::Slice data) {
auto obj = create_tl_object<ton_api::hashable_blockSignature>(desc.compute_hash(data));
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* r, td::Slice data, HashType hash) {
if (!r || r->get_size() < sizeof(SessionBlockCandidateSignature)) {
return false;
}
auto R = static_cast<const SessionBlockCandidateSignature*>(r);
return R->hash_ == hash && R->data_.ubegin() == data.ubegin() && R->data_.size() == data.size();
}
static auto lookup(ValidatorSessionDescription& desc, td::Slice data, HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, data, hash)) {
desc.on_reuse();
return static_cast<const SessionBlockCandidateSignature*>(r);
}
return static_cast<const SessionBlockCandidateSignature*>(nullptr);
}
static SessionBlockCandidateSignature* create(ValidatorSessionDescription& desc, td::BufferSlice value) {
auto hash = create_hash(desc, value.as_slice());
auto d = static_cast<td::uint8*>(desc.alloc(value.size(), 8, false));
td::MutableSlice s{d, value.size()};
s.copy_from(value.as_slice());
return new (desc, true) SessionBlockCandidateSignature{desc, s, hash};
}
static const SessionBlockCandidateSignature* move_to_persistent(ValidatorSessionDescription& desc,
const SessionBlockCandidateSignature* b) {
if (desc.is_persistent(b)) {
return b;
}
CHECK(desc.is_persistent(b->data_.ubegin()));
auto r = lookup(desc, b->data_, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) SessionBlockCandidateSignature{desc, b->data_, b->hash_};
}
static const SessionBlockCandidateSignature* merge(ValidatorSessionDescription& desc,
const SessionBlockCandidateSignature* l,
const SessionBlockCandidateSignature* r);
SessionBlockCandidateSignature(ValidatorSessionDescription& desc, td::Slice data, HashType hash)
: RootObject(sizeof(SessionBlockCandidateSignature)), data_{data}, hash_(std::move(hash)) {
desc.update_hash(this, hash_);
}
td::BufferSlice value() const {
return td::BufferSlice{data_};
}
td::Slice as_slice() const {
return data_;
}
auto get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
private:
const td::Slice data_;
const HashType hash_;
};
using SessionBlockCandidateSignatureVector = CntVector<const SessionBlockCandidateSignature*>;
class SentBlock : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, td::uint32 src_idx, ValidatorSessionRootHash root_hash,
ValidatorSessionFileHash file_hash,
ValidatorSessionCollatedDataFileHash collated_data_file_hash) {
auto obj = create_tl_object<ton_api::hashable_sentBlock>(src_idx, get_vs_hash(desc, root_hash),
get_vs_hash(desc, file_hash),
get_vs_hash(desc, collated_data_file_hash));
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* root_object, td::uint32 src_idx, const ValidatorSessionRootHash& root_hash,
const ValidatorSessionFileHash& file_hash,
const ValidatorSessionCollatedDataFileHash& collated_data_file_hash, HashType hash) {
if (!root_object || root_object->get_size() < sizeof(SentBlock)) {
return false;
}
auto obj = static_cast<const SentBlock*>(root_object);
return obj->src_idx_ == src_idx && obj->root_hash_ == root_hash && obj->file_hash_ == file_hash &&
obj->collated_data_file_hash_ == collated_data_file_hash && obj->hash_ == hash;
}
static auto lookup(ValidatorSessionDescription& desc, td::uint32 src_idx, const ValidatorSessionRootHash& root_hash,
const ValidatorSessionFileHash& file_hash,
const ValidatorSessionCollatedDataFileHash& collated_data_file_hash, HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, src_idx, root_hash, file_hash, collated_data_file_hash, hash)) {
desc.on_reuse();
return static_cast<const SentBlock*>(r);
}
return static_cast<const SentBlock*>(nullptr);
}
static const SentBlock* create(ValidatorSessionDescription& desc, td::uint32 src_idx,
const ValidatorSessionRootHash& root_hash, const ValidatorSessionFileHash& file_hash,
const ValidatorSessionCollatedDataFileHash& collated_data_file_hash) {
auto hash = create_hash(desc, src_idx, root_hash, file_hash, collated_data_file_hash);
auto r = lookup(desc, src_idx, root_hash, file_hash, collated_data_file_hash, hash, true);
if (r) {
return r;
}
auto candidate_id = desc.candidate_id(src_idx, root_hash, file_hash, collated_data_file_hash);
return new (desc, true) SentBlock{desc, src_idx, root_hash, file_hash, collated_data_file_hash, candidate_id, hash};
}
static const SentBlock* create(ValidatorSessionDescription& desc, const ValidatorSessionCandidateId& zero) {
CHECK(zero.is_zero());
auto hash = create_hash(desc, 0, ValidatorSessionRootHash::zero(), ValidatorSessionFileHash::zero(),
ValidatorSessionCollatedDataFileHash::zero());
return new (desc, true) SentBlock{desc,
0,
ValidatorSessionRootHash::zero(),
ValidatorSessionFileHash::zero(),
ValidatorSessionCollatedDataFileHash::zero(),
zero,
hash};
}
static const SentBlock* move_to_persistent(ValidatorSessionDescription& desc, const SentBlock* b) {
if (desc.is_persistent(b)) {
return b;
}
auto r = lookup(desc, b->src_idx_, b->root_hash_, b->file_hash_, b->collated_data_file_hash_, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) SentBlock{
desc, b->src_idx_, b->root_hash_, b->file_hash_, b->collated_data_file_hash_, b->candidate_id_, b->hash_};
}
SentBlock(ValidatorSessionDescription& desc, td::uint32 src_idx, ValidatorSessionRootHash root_hash,
ValidatorSessionFileHash file_hash, ValidatorSessionCollatedDataFileHash collated_data_file_hash,
ValidatorSessionCandidateId candidate_id, HashType hash)
: RootObject(sizeof(SentBlock))
, src_idx_(src_idx)
, root_hash_(std::move(root_hash))
, file_hash_(std::move(file_hash))
, collated_data_file_hash_(std::move(collated_data_file_hash))
, candidate_id_(candidate_id)
, hash_(std::move(hash)) {
desc.update_hash(this, hash_);
}
auto get_src_idx() const {
return src_idx_;
}
auto get_root_hash() const {
return root_hash_;
}
auto get_file_hash() const {
return file_hash_;
}
auto get_collated_data_file_hash() const {
return collated_data_file_hash_;
}
static ValidatorSessionCandidateId get_block_id(const SentBlock* block) {
return block ? block->candidate_id_ : skip_round_candidate_id();
}
HashType get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
bool operator<(const SentBlock& block) const {
if (src_idx_ < block.src_idx_) {
return true;
}
if (src_idx_ > block.src_idx_) {
return false;
}
if (candidate_id_ < block.candidate_id_) {
return true;
}
return false;
}
struct Compare {
bool operator()(const SentBlock* a, const SentBlock* b) const {
return *a < *b;
}
};
private:
const td::uint32 src_idx_;
const ValidatorSessionRootHash root_hash_;
const ValidatorSessionFileHash file_hash_;
const ValidatorSessionCollatedDataFileHash collated_data_file_hash_;
const ValidatorSessionCandidateId candidate_id_;
const HashType hash_;
};
class SessionBlockCandidate : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, HashType block, HashType approved) {
auto obj = create_tl_object<ton_api::hashable_blockCandidate>(block, approved);
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* r, const SentBlock* block, const SessionBlockCandidateSignatureVector* approved,
HashType hash) {
if (!r || r->get_size() < sizeof(SessionBlockCandidate)) {
return false;
}
auto R = static_cast<const SessionBlockCandidate*>(r);
return R->block_ == block && R->approved_by_ == approved && R->hash_ == hash;
}
static auto lookup(ValidatorSessionDescription& desc, const SentBlock* block,
const SessionBlockCandidateSignatureVector* approved, HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, block, approved, hash)) {
desc.on_reuse();
return static_cast<const SessionBlockCandidate*>(r);
}
return static_cast<const SessionBlockCandidate*>(nullptr);
}
static const SessionBlockCandidate* create(ValidatorSessionDescription& desc, const SentBlock* block,
const SessionBlockCandidateSignatureVector* approved) {
auto hash = create_hash(desc, get_vs_hash(desc, block), get_vs_hash(desc, approved));
auto r = lookup(desc, block, approved, hash, true);
if (r) {
return r;
}
return new (desc, true) SessionBlockCandidate(desc, block, approved, hash);
}
static const SessionBlockCandidate* create(ValidatorSessionDescription& desc, const SentBlock* block) {
std::vector<const SessionBlockCandidateSignature*> v;
v.resize(desc.get_total_nodes(), nullptr);
auto vec = SessionBlockCandidateSignatureVector::create(desc, std::move(v));
return create(desc, block, vec);
}
static const SessionBlockCandidate* move_to_persistent(ValidatorSessionDescription& desc,
const SessionBlockCandidate* b) {
if (desc.is_persistent(b)) {
return b;
}
auto block = SentBlock::move_to_persistent(desc, b->block_);
auto approved = SessionBlockCandidateSignatureVector::move_to_persistent(desc, b->approved_by_);
auto r = lookup(desc, block, approved, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) SessionBlockCandidate{desc, block, approved, b->hash_};
}
SessionBlockCandidate(ValidatorSessionDescription& desc, const SentBlock* block,
const SessionBlockCandidateSignatureVector* approved, HashType hash)
: RootObject{sizeof(SessionBlockCandidate)}, block_(block), approved_by_(approved), hash_(hash) {
desc.update_hash(this, hash_);
}
static const SessionBlockCandidate* merge(ValidatorSessionDescription& desc, const SessionBlockCandidate* l,
const SessionBlockCandidate* r);
auto get_block() const {
return block_;
}
auto get_id() const {
return SentBlock::get_block_id(block_);
}
auto get_src_idx() const {
return block_ ? block_->get_src_idx() : std::numeric_limits<td::uint32>::max();
}
bool check_block_is_approved_by(td::uint32 src_idx) const {
return approved_by_->at(src_idx);
}
bool check_block_is_approved(ValidatorSessionDescription& desc) const;
auto get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
auto get_approvers_list() const {
return approved_by_;
}
static const SessionBlockCandidate* push(ValidatorSessionDescription& desc, const SessionBlockCandidate* state,
td::uint32 src_idx, const SessionBlockCandidateSignature* sig) {
CHECK(state);
if (state->approved_by_->at(src_idx)) {
return state;
}
return create(desc, state->block_,
SessionBlockCandidateSignatureVector::change(desc, state->approved_by_, src_idx, sig));
}
class Compare {
public:
bool operator()(const SessionBlockCandidate* l, const SessionBlockCandidate* r) {
return l->get_id() < r->get_id();
}
};
private:
const SentBlock* block_;
const SessionBlockCandidateSignatureVector* approved_by_;
const HashType hash_;
};
class SessionVoteCandidate : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, HashType block, HashType voted) {
auto obj = create_tl_object<ton_api::hashable_blockVoteCandidate>(block, voted);
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* r, const SentBlock* block, const CntVector<bool>* voted, HashType hash) {
if (!r || r->get_size() < sizeof(SessionVoteCandidate)) {
return false;
}
auto R = static_cast<const SessionVoteCandidate*>(r);
return R->block_ == block && R->voted_by_ == voted && R->hash_ == hash;
}
static auto lookup(ValidatorSessionDescription& desc, const SentBlock* block, const CntVector<bool>* voted,
HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, block, voted, hash)) {
desc.on_reuse();
return static_cast<const SessionVoteCandidate*>(r);
}
return static_cast<const SessionVoteCandidate*>(nullptr);
}
static const SessionVoteCandidate* create(ValidatorSessionDescription& desc, const SentBlock* block,
const CntVector<bool>* voted) {
auto hash = create_hash(desc, get_vs_hash(desc, block), get_vs_hash(desc, voted));
auto r = lookup(desc, block, voted, hash, true);
if (r) {
return r;
}
return new (desc, true) SessionVoteCandidate(desc, block, voted, hash);
}
static const SessionVoteCandidate* create(ValidatorSessionDescription& desc, const SentBlock* block) {
std::vector<bool> v;
v.resize(desc.get_total_nodes(), false);
auto vec = CntVector<bool>::create(desc, std::move(v));
return create(desc, block, vec);
}
static const SessionVoteCandidate* move_to_persistent(ValidatorSessionDescription& desc,
const SessionVoteCandidate* b) {
if (desc.is_persistent(b)) {
return b;
}
auto block = SentBlock::move_to_persistent(desc, b->block_);
auto voted = CntVector<bool>::move_to_persistent(desc, b->voted_by_);
auto r = lookup(desc, block, voted, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) SessionVoteCandidate{desc, block, voted, b->hash_};
}
SessionVoteCandidate(ValidatorSessionDescription& desc, const SentBlock* block, const CntVector<bool>* voted,
HashType hash)
: RootObject{sizeof(SessionVoteCandidate)}, block_(block), voted_by_(voted), hash_(hash) {
desc.update_hash(this, hash_);
}
static const SessionVoteCandidate* merge(ValidatorSessionDescription& desc, const SessionVoteCandidate* l,
const SessionVoteCandidate* r);
auto get_block() const {
return block_;
}
auto get_id() const {
return SentBlock::get_block_id(block_);
}
auto get_src_idx() const {
return block_ ? block_->get_src_idx() : std::numeric_limits<td::uint32>::max();
}
bool check_block_is_voted_by(td::uint32 src_idx) const {
return voted_by_->at(src_idx);
}
bool check_block_is_voted(ValidatorSessionDescription& desc) const;
auto get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
auto get_voters_list() const {
return voted_by_;
}
static const SessionVoteCandidate* push(ValidatorSessionDescription& desc, const SessionVoteCandidate* state,
td::uint32 src_idx) {
CHECK(state);
if (state->voted_by_->at(src_idx)) {
return state;
}
return create(desc, state->block_, CntVector<bool>::change(desc, state->voted_by_, src_idx, true));
}
class Compare {
public:
bool operator()(const SessionVoteCandidate* l, const SessionVoteCandidate* r) {
return l->get_id() < r->get_id();
}
};
private:
const SentBlock* block_;
const CntVector<bool>* voted_by_;
const HashType hash_;
};
//using SentBlockVector = CntSortedVector<const SentBlock*, SentBlock::Compare>;
class ValidatorSessionRoundState;
class ValidatorSessionOldRoundState : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, td::uint32 seqno, HashType block, HashType signatures,
@ -582,188 +178,6 @@ class ValidatorSessionOldRoundState : public ValidatorSessionDescription::RootOb
const HashType hash_;
};
using VoteVector = CntSortedVector<const SessionVoteCandidate*, SessionVoteCandidate::Compare>;
using ApproveVector = CntSortedVector<const SessionBlockCandidate*, SessionBlockCandidate::Compare>;
class ValidatorSessionRoundAttemptState : public ValidatorSessionDescription::RootObject {
public:
static HashType create_hash(ValidatorSessionDescription& desc, td::uint32 seqno, HashType votes,
HashType precommitted, bool vote_for_inited, HashType vote_for) {
auto obj = create_tl_object<ton_api::hashable_validatorSessionRoundAttempt>(seqno, votes, precommitted,
vote_for_inited, vote_for);
return desc.compute_hash(serialize_tl_object(obj, true).as_slice());
}
static bool compare(const RootObject* r, td::uint32 seqno, const VoteVector* votes,
const CntVector<bool>* precommitted, const SentBlock* vote_for, bool vote_for_inited,
HashType hash) {
if (!r || r->get_size() < sizeof(ValidatorSessionRoundAttemptState)) {
return false;
}
auto R = static_cast<const ValidatorSessionRoundAttemptState*>(r);
return R->seqno_ == seqno && R->votes_ == votes && R->precommitted_ == precommitted && R->vote_for_ == vote_for &&
R->vote_for_inited_ == vote_for_inited && R->hash_ == hash;
}
static auto lookup(ValidatorSessionDescription& desc, td::uint32 seqno, const VoteVector* votes,
const CntVector<bool>* precommitted, const SentBlock* vote_for, bool vote_for_inited,
HashType hash, bool temp) {
auto r = desc.get_by_hash(hash, temp);
if (compare(r, seqno, votes, precommitted, vote_for, vote_for_inited, hash)) {
desc.on_reuse();
return static_cast<const ValidatorSessionRoundAttemptState*>(r);
}
return static_cast<const ValidatorSessionRoundAttemptState*>(nullptr);
}
static const ValidatorSessionRoundAttemptState* move_to_persistent(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* b) {
if (desc.is_persistent(b)) {
return b;
}
auto votes = VoteVector::move_to_persistent(desc, b->votes_);
auto precommitted = CntVector<bool>::move_to_persistent(desc, b->precommitted_);
auto vote_for = SentBlock::move_to_persistent(desc, b->vote_for_);
auto r = lookup(desc, b->seqno_, votes, precommitted, vote_for, b->vote_for_inited_, b->hash_, false);
if (r) {
return r;
}
return new (desc, false) ValidatorSessionRoundAttemptState{desc, b->seqno_, votes, precommitted,
vote_for, b->vote_for_inited_, b->hash_};
}
static const ValidatorSessionRoundAttemptState* create(ValidatorSessionDescription& desc, td::uint32 seqno,
const VoteVector* votes, const CntVector<bool>* precommitted,
const SentBlock* vote_for, bool vote_for_inited) {
auto hash = create_hash(desc, seqno, get_vs_hash(desc, votes), get_vs_hash(desc, precommitted),
get_vs_hash(desc, vote_for), vote_for_inited);
auto r = lookup(desc, seqno, votes, precommitted, vote_for, vote_for_inited, hash, true);
if (r) {
return r;
}
return new (desc, true)
ValidatorSessionRoundAttemptState(desc, seqno, votes, precommitted, vote_for, vote_for_inited, hash);
}
static const ValidatorSessionRoundAttemptState* create(ValidatorSessionDescription& desc, td::uint32 seqno) {
std::vector<bool> x;
x.resize(desc.get_total_nodes(), false);
auto p = CntVector<bool>::create(desc, std::move(x));
return create(desc, seqno, nullptr, p, nullptr, false);
}
ValidatorSessionRoundAttemptState(ValidatorSessionDescription& desc, td::uint32 seqno, const VoteVector* votes,
const CntVector<bool>* precommitted, const SentBlock* vote_for,
bool vote_for_inited, HashType hash)
: RootObject{sizeof(ValidatorSessionRoundAttemptState)}
, seqno_(seqno)
, votes_(votes)
, precommitted_(precommitted)
, vote_for_(vote_for)
, vote_for_inited_(vote_for_inited)
, hash_(std::move(hash)) {
desc.update_hash(this, hash_);
}
auto get_hash(ValidatorSessionDescription& desc) const {
return hash_;
}
auto get_seqno() const {
return seqno_;
}
auto get_votes() const {
return votes_;
}
auto get_precommits() const {
return precommitted_;
}
const SentBlock* get_voted_block(ValidatorSessionDescription& desc, bool& f) const;
const SentBlock* get_vote_for_block(ValidatorSessionDescription& desc, bool& f) const {
f = vote_for_inited_;
return vote_for_;
}
bool check_attempt_is_precommitted(ValidatorSessionDescription& desc) const;
bool check_vote_received_from(td::uint32 src_idx) const;
bool check_precommit_received_from(td::uint32 src_idx) const;
bool operator<(const ValidatorSessionRoundAttemptState& right) const {
return seqno_ < right.seqno_;
}
struct Compare {
bool operator()(const ValidatorSessionRoundAttemptState* a, const ValidatorSessionRoundAttemptState* b) const {
return *a < *b;
}
};
static const ValidatorSessionRoundAttemptState* merge(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* left,
const ValidatorSessionRoundAttemptState* right);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_message_voteFor& act,
const ValidatorSessionRoundState* round);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_message_vote& act,
const ValidatorSessionRoundState* round);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_message_precommit& act,
const ValidatorSessionRoundState* round);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_message_empty& act,
const ValidatorSessionRoundState* round);
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ton_api::validatorSession_round_Message* action,
const ValidatorSessionRoundState* round);
template <class T>
static const ValidatorSessionRoundAttemptState* action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att, const T& action,
const ValidatorSessionRoundState* round) {
UNREACHABLE();
}
static const ValidatorSessionRoundAttemptState* try_vote(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ValidatorSessionRoundState* round,
const ton_api::validatorSession_round_Message* cmp,
bool& made);
static const ValidatorSessionRoundAttemptState* try_precommit(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ValidatorSessionRoundState* round,
const ton_api::validatorSession_round_Message* cmp,
bool& made);
static const ValidatorSessionRoundAttemptState* make_one(ValidatorSessionDescription& desc,
const ValidatorSessionRoundAttemptState* state,
td::uint32 src_idx, td::uint32 att,
const ValidatorSessionRoundState* round,
const ton_api::validatorSession_round_Message* cmp,
bool& made);
tl_object_ptr<ton_api::validatorSession_round_Message> create_action(ValidatorSessionDescription& desc,
const ValidatorSessionRoundState* round,
td::uint32 src_idx, td::uint32 att) const;
void dump(ValidatorSessionDescription& desc, td::StringBuilder& sb) const;
private:
const td::uint32 seqno_;
const VoteVector* votes_;
const CntVector<bool>* precommitted_;
const SentBlock* vote_for_;
const bool vote_for_inited_;
const HashType hash_;
};
using AttemptVector =
CntSortedVector<const ValidatorSessionRoundAttemptState*, ValidatorSessionRoundAttemptState::Compare>;
class ValidatorSessionRoundState : public ValidatorSessionDescription::RootObject {
public:

View file

@ -27,6 +27,12 @@ namespace ton {
namespace validatorsession {
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_WARNING) = verbosity_WARNING;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_NOTICE) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_INFO) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_DEBUG) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(VALIDATOR_SESSION_EXTRA_DEBUG) = verbosity_DEBUG + 1;
using ValidatorSessionRootHash = td::Bits256;
using ValidatorSessionFileHash = td::Bits256;
using ValidatorSessionCollatedDataFileHash = td::Bits256;

View file

@ -204,7 +204,23 @@ void ValidatorSessionImpl::preprocess_block(catchain::CatChainBlock *block) {
<< "ms: state=" << state->get_hash(description());
}
void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice data) {
bool ValidatorSessionImpl::ensure_candidate_unique(td::uint32 src_idx, td::uint32 round,
ValidatorSessionCandidateId block_id) {
auto it = src_round_candidate_[src_idx].find(round);
if (it != src_round_candidate_[src_idx].end() && it->second != block_id) {
VLOG(VALIDATOR_SESSION_WARNING) << this << "[node " << description_->get_source_adnl_id(src_idx) << "][candidate "
<< block_id << "]: this node already has candidate in round " << round;
return false;
}
src_round_candidate_[src_idx][round] = block_id;
return true;
}
void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice data,
td::optional<ValidatorSessionCandidateId> expected_id,
bool is_overlay_broadcast) {
// Note: src is not necessarily equal to the sender of this message:
// If requested using get_broadcast_p2p, src is the creator of the block, sender possibly is some other node.
auto src_idx = description().get_source_idx(src);
auto R = fetch_tl_object<ton_api::validatorSession_candidate>(data.clone(), true);
if (R.is_error()) {
@ -231,6 +247,12 @@ void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice
auto block_round = static_cast<td::uint32>(candidate->round_);
auto block_id = description().candidate_id(src_idx, candidate->root_hash_, file_hash, collated_data_file_hash);
if (expected_id && expected_id.value() != block_id) {
VLOG(VALIDATOR_SESSION_WARNING) << this << "[node " << src << "][broadcast " << sha256_bits256(data.as_slice())
<< "]: id mismatch";
return;
}
if ((td::int32)block_round < (td::int32)cur_round_ - MAX_PAST_ROUND_BLOCK ||
block_round >= cur_round_ + MAX_FUTURE_ROUND_BLOCK) {
VLOG(VALIDATOR_SESSION_NOTICE) << this << "[node " << src << "][broadcast " << block_id
@ -251,6 +273,10 @@ void ValidatorSessionImpl::process_broadcast(PublicKeyHash src, td::BufferSlice
return;
}
if (is_overlay_broadcast && !ensure_candidate_unique(src_idx, block_round, block_id)) {
return;
}
blocks_[block_id] = std::move(candidate);
VLOG(VALIDATOR_SESSION_WARNING) << this << ": received broadcast " << block_id;
@ -509,7 +535,11 @@ void ValidatorSessionImpl::try_approve_block(const SentBlock *block) {
}
if (block) {
auto T = td::Timestamp::at(round_started_at_.at() + description().get_delay(block->get_src_idx()) + 2.0);
if (!ensure_candidate_unique(block->get_src_idx(), cur_round_, SentBlock::get_block_id(block))) {
return;
}
auto T = td::Timestamp::at(round_started_at_.at() + description().get_delay(block->get_src_idx()) +
REQUEST_BROADCAST_P2P_DELAY);
auto it = blocks_.find(block_id);
if (it != blocks_.end()) {
@ -546,16 +576,18 @@ void ValidatorSessionImpl::try_approve_block(const SentBlock *block) {
auto id = description().get_source_id(v[td::Random::fast(0, static_cast<td::int32>(v.size() - 1))]);
auto src_id = description().get_source_id(block->get_src_idx());
active_requests_.insert(block_id);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id, src_id, print_id = print_id(),
hash = block_id, round = cur_round_](td::Result<td::BufferSlice> R) {
td::actor::send_closure(SelfId, &ValidatorSessionImpl::end_request, round, hash);
if (R.is_error()) {
VLOG(VALIDATOR_SESSION_WARNING)
<< print_id << ": failed to get candidate " << hash << " from " << id << ": " << R.move_as_error();
} else {
td::actor::send_closure(SelfId, &ValidatorSessionImpl::process_broadcast, src_id, R.move_as_ok());
}
});
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), id, src_id, print_id = print_id(), hash = block_id, round = cur_round_,
candidate_id = SentBlock::get_block_id(block)](td::Result<td::BufferSlice> R) {
td::actor::send_closure(SelfId, &ValidatorSessionImpl::end_request, round, hash);
if (R.is_error()) {
VLOG(VALIDATOR_SESSION_WARNING) << print_id << ": failed to get candidate " << hash << " from " << id
<< ": " << R.move_as_error();
} else {
td::actor::send_closure(SelfId, &ValidatorSessionImpl::process_broadcast, src_id, R.move_as_ok(),
candidate_id, false);
}
});
get_broadcast_p2p(id, block->get_file_hash(), block->get_collated_data_file_hash(),
description().get_source_id(block->get_src_idx()), cur_round_, block->get_root_hash(),
@ -587,10 +619,11 @@ void ValidatorSessionImpl::get_broadcast_p2p(PublicKeyHash node, ValidatorSessio
round,
create_tl_object<ton_api::validatorSession_candidateId>(src.tl(), root_hash, file_hash, collated_data_file_hash));
td::actor::send_closure(catchain_, &catchain::CatChain::send_query_via, node, "download candidate",
std::move(promise), timeout, serialize_tl_object(obj, true),
description().opts().max_block_size + description().opts().max_collated_data_size + 1024,
rldp_);
td::actor::send_closure(
catchain_, &catchain::CatChain::send_query_via, node, "download candidate", std::move(promise), timeout,
serialize_tl_object(obj, true),
description().opts().max_block_size + description().opts().max_collated_data_size + MAX_CANDIDATE_EXTRA_SIZE,
rldp_);
}
void ValidatorSessionImpl::check_sign_slot() {
@ -746,7 +779,6 @@ void ValidatorSessionImpl::on_new_round(td::uint32 round) {
while (cur_round_ < round) {
auto block = real_state_->get_committed_block(description(), cur_round_);
//CHECK(block);
auto sigs = real_state_->get_committed_block_signatures(description(), cur_round_);
CHECK(sigs);
auto approve_sigs = real_state_->get_committed_block_approve_signatures(description(), cur_round_);
@ -839,7 +871,8 @@ void ValidatorSessionImpl::on_catchain_started() {
auto broadcast = create_tl_object<ton_api::validatorSession_candidate>(
src.tl(), round, root_hash, std::move(B.data), std::move(B.collated_data));
td::actor::send_closure(SelfId, &ValidatorSessionImpl::process_broadcast, src,
serialize_tl_object(broadcast, true));
serialize_tl_object(broadcast, true), td::optional<ValidatorSessionCandidateId>(),
false);
}
});
callback_->get_approved_candidate(description().get_source_public_key(x->get_src_idx()), x->get_root_hash(),
@ -867,6 +900,7 @@ ValidatorSessionImpl::ValidatorSessionImpl(catchain::CatChainSessionId session_i
, overlay_manager_(overlays)
, allow_unsafe_self_blocks_resync_(allow_unsafe_self_blocks_resync) {
description_ = ValidatorSessionDescription::create(std::move(opts), nodes, local_id);
src_round_candidate_.resize(description_->get_total_nodes());
}
void ValidatorSessionImpl::start() {

View file

@ -74,6 +74,8 @@ class ValidatorSessionImpl : public ValidatorSession {
td::BufferSlice signature_;
std::map<ValidatorSessionCandidateId, tl_object_ptr<ton_api::validatorSession_candidate>> blocks_;
// src_round_candidate_[src_id][round] -> candidate id
std::vector<std::map<td::uint32, ValidatorSessionCandidateId>> src_round_candidate_;
catchain::CatChainSessionId unique_hash_;
@ -110,7 +112,8 @@ class ValidatorSessionImpl : public ValidatorSession {
td::actor::send_closure(id_, &ValidatorSessionImpl::preprocess_block, block);
}
void process_broadcast(const PublicKeyHash &src, td::BufferSlice data) override {
td::actor::send_closure(id_, &ValidatorSessionImpl::process_broadcast, src, std::move(data));
td::actor::send_closure(id_, &ValidatorSessionImpl::process_broadcast, src, std::move(data),
td::optional<ValidatorSessionCandidateId>(), true);
}
void process_message(const PublicKeyHash &src, td::BufferSlice data) override {
td::actor::send_closure(id_, &ValidatorSessionImpl::process_message, src, std::move(data));
@ -176,7 +179,9 @@ class ValidatorSessionImpl : public ValidatorSession {
void process_blocks(std::vector<catchain::CatChainBlock *> blocks);
void finished_processing();
void preprocess_block(catchain::CatChainBlock *block);
void process_broadcast(PublicKeyHash src, td::BufferSlice data);
bool ensure_candidate_unique(td::uint32 src_idx, td::uint32 round, ValidatorSessionCandidateId block_id);
void process_broadcast(PublicKeyHash src, td::BufferSlice data, td::optional<ValidatorSessionCandidateId> expected_id,
bool is_overlay_broadcast);
void process_message(PublicKeyHash src, td::BufferSlice data);
void process_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
@ -208,6 +213,8 @@ class ValidatorSessionImpl : public ValidatorSession {
static const size_t MAX_REJECT_REASON_SIZE = 1024;
static const td::int32 MAX_FUTURE_ROUND_BLOCK = 100;
static const td::int32 MAX_PAST_ROUND_BLOCK = 20;
constexpr static const double REQUEST_BROADCAST_P2P_DELAY = 2.0;
static const td::uint32 MAX_CANDIDATE_EXTRA_SIZE = 1024;
};
} // namespace validatorsession