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:
commit
e4e77c16c5
463 changed files with 29976 additions and 2517 deletions
|
@ -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})
|
||||
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
486
validator-session/validator-session-round-attempt-state.cpp
Normal file
486
validator-session/validator-session-round-attempt-state.cpp
Normal 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
|
620
validator-session/validator-session-round-attempt-state.h
Normal file
620
validator-session/validator-session-round-attempt-state.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue