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

Update catchain (#432)

* Update catchain

* Update ton_api.tlo
This commit is contained in:
SpyCheese 2022-08-08 09:31:36 +03:00 committed by GitHub
parent 5101b404a4
commit 8d7f1bba73
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 617 additions and 477 deletions

View file

@ -1,27 +1,26 @@
# TON
# TON CatChain
Main TON monorepo, which includes the code of the node/validator, lite-client, tonlib, FunC compiler, etc.
## Updates flow:
* **master branch** - mainnet is running on this stable branch.
Only emergency updates, urgent updates, or updates that do not affect the main codebase (GitHub workflows / docker images / documentation) are committed directly to this branch.
* **testnet branch** - testnet is running on this branch. The branch contains a set of new updates. After testing, the testnet branch is merged into the master branch and then a new set of updates is added to testnet branch.
* **backlog** - other branches that are candidates to getting into the testnet branch in the next iteration.
Usually, the response to your pull request will indicate which section it falls into.
## "Soft" Pull Request rules
* Thou shall not merge your own PRs, at least one person should review the PR and merge it (4-eyes rule)
* Thou shall make sure that workflows are cleanly completed for your PR before considering merge
## Workflows responsibility
If a CI workflow fails not because of your changes but workflow issues, try to fix it yourself or contact one of the persons listed below via Telegram messenger:
* **C/C++ CI (ccpp-linux.yml)**: TBD
* **C/C++ CI Win64 Compile (ccpp-win64.yml)**: TBD
| Name | Fixed? | Comment |
|------|---|---------------------------------------|
|CA2-01| ✔️ | |
|CA2-02| ✔️ | |
|CA5-01| ✔️ | `hash(payload)` now also covers block data.<br>This behavior is enabled by a flag in config. |
|CA5-02| ✔️ | Size of a block is now limited (16kb).<br>Block height is now limited, and blocks from misbehaviouring nodes are now ignored.<br>See `doc/catchain-dos.md` for details. |
|CA5-03| ✔️ | |
|CA5-04| ✔️ | |
|CA5-05| ✔️ | |
|CA5-06| ✔️ | |
|CA5-07| ✔️ | |
|CA5-08| ✔️ | |
|CA5-09| ✔️ | |
|CA5-10| ✔️ | |
|CA5-11| ✔️ | |
|CAA-01| ✔️ | Fixed in the same way as CA5-01 (hash now covers block data). |
|CAA-02| ✔️ | |
|CAE-01| ✔️ | |
|CAN-01| ✔️ | |
|CAN-02| ✔️ | |
|CAT-01| ✔️ | |
|CAT-02| ✔️ | |
|CAT-03| ✔️ | |
|CAT-04| ✔️ | |

View file

@ -22,8 +22,8 @@ namespace ton {
namespace catchain {
std::unique_ptr<CatChainBlock> CatChainBlock::create(td::uint32 src, td::uint32 fork, PublicKeyHash src_hash,
CatChainBlockHeight height, CatChainBlockHash hash,
std::unique_ptr<CatChainBlock> CatChainBlock::create(td::uint32 src, td::uint32 fork, const PublicKeyHash &src_hash,
CatChainBlockHeight height, const CatChainBlockHash &hash,
td::SharedSlice payload, CatChainBlock *prev,
std::vector<CatChainBlock *> deps,
std::vector<CatChainBlockHeight> vt) {
@ -31,10 +31,10 @@ std::unique_ptr<CatChainBlock> CatChainBlock::create(td::uint32 src, td::uint32
std::move(deps), std::move(vt));
}
CatChainBlockImpl::CatChainBlockImpl(td::uint32 src, td::uint32 fork, PublicKeyHash src_hash,
CatChainBlockHeight height, CatChainBlockHash hash, td::SharedSlice payload,
CatChainBlock *prev, std::vector<CatChainBlock *> deps,
std::vector<CatChainBlockHeight> vt)
CatChainBlockImpl::CatChainBlockImpl(td::uint32 src, td::uint32 fork, const PublicKeyHash &src_hash,
CatChainBlockHeight height, const CatChainBlockHash &hash,
td::SharedSlice payload, CatChainBlock *prev,
std::vector<CatChainBlock *> deps, std::vector<CatChainBlockHeight> vt)
: src_(src)
, fork_(fork)
, src_hash_(src_hash)
@ -47,7 +47,7 @@ CatChainBlockImpl::CatChainBlockImpl(td::uint32 src, td::uint32 fork, PublicKeyH
}
bool CatChainBlockImpl::is_descendant_of(CatChainBlock *block) {
auto fork = block->fork();
td::uint32 fork = block->fork();
if (fork >= vt_.size()) {
return false;
}

View file

@ -103,8 +103,8 @@ class CatChainBlockImpl : public CatChainBlock {
bool is_descendant_of(CatChainBlock *block) override;
CatChainBlockImpl(td::uint32 src, td::uint32 fork, PublicKeyHash src_hash, CatChainBlockHeight height,
CatChainBlockHash hash, td::SharedSlice payload, CatChainBlock *prev,
CatChainBlockImpl(td::uint32 src, td::uint32 fork, const PublicKeyHash &src_hash, CatChainBlockHeight height,
const CatChainBlockHash &hash, td::SharedSlice payload, CatChainBlock *prev,
std::vector<CatChainBlock *> deps, std::vector<CatChainBlockHeight> vt);
};

View file

@ -33,7 +33,7 @@ void CatChainReceivedBlockImpl::initialize(tl_object_ptr<ton_api::catchain_block
}
payload_ = std::move(payload);
CHECK(payload_.size() > 0);
CHECK(!payload_.empty());
prev_ = dynamic_cast<CatChainReceivedBlockImpl *>(chain_->create_block(std::move(block->data_->prev_)));
CHECK(prev_ != nullptr);
@ -51,7 +51,7 @@ void CatChainReceivedBlockImpl::initialize(tl_object_ptr<ton_api::catchain_block
set_ill();
return;
}
for (auto &X : block_deps_) {
for (CatChainReceivedBlockImpl *X : block_deps_) {
if (X->is_ill()) {
set_ill();
return;
@ -63,17 +63,17 @@ void CatChainReceivedBlockImpl::initialize(tl_object_ptr<ton_api::catchain_block
if (!prev_->delivered()) {
pending_deps++;
} else {
update_deps(prev_);
update_vt(prev_);
}
if (!prev_->delivered()) {
prev_->add_rev_dep(this);
}
}
for (auto &X : block_deps_) {
for (CatChainReceivedBlockImpl *X : block_deps_) {
if (!X->delivered()) {
pending_deps++;
} else {
update_deps(X);
update_vt(X);
}
if (!X->delivered()) {
X->add_rev_dep(this);
@ -121,11 +121,11 @@ void CatChainReceivedBlockImpl::initialize_fork() {
}
}
if (deps_.size() < fork_id_ + 1) {
deps_.resize(fork_id_ + 1, 0);
if (vt_.size() < fork_id_ + 1) {
vt_.resize(fork_id_ + 1, 0);
}
CHECK(deps_[fork_id_] < height_);
deps_[fork_id_] = height_;
CHECK(vt_[fork_id_] < height_);
vt_[fork_id_] = height_;
}
void CatChainReceivedBlockImpl::pre_deliver(ton_api::catchain_block_data_fork &b) {
@ -153,7 +153,7 @@ void CatChainReceivedBlockImpl::pre_deliver(ton_api::catchain_block_data_fork &b
return;
}
auto S = chain_->get_source(b.left_->src_);
CatChainReceiverSource *S = chain_->get_source(b.left_->src_);
S->on_found_fork_proof(
create_serialize_tl_object<ton_api::catchain_block_data_fork>(std::move(b.left_), std::move(b.right_)));
S->blame(fork_id_, height_);
@ -173,15 +173,15 @@ void CatChainReceivedBlockImpl::pre_deliver() {
CHECK(pending_deps_ == 0);
CHECK(in_db_);
auto M = chain_->get_source(source_id_);
CatChainReceiverSource *M = chain_->get_source(source_id_);
auto d = prev_ ? &prev_->deps_ : nullptr;
std::vector<CatChainBlockHeight> *d = prev_ ? &prev_->vt_ : nullptr;
for (auto &X : block_deps_) {
auto S = chain_->get_source(X->get_source_id());
auto &f = S->get_forks();
for (CatChainReceivedBlockImpl *X : block_deps_) {
CatChainReceiverSource *S = chain_->get_source(X->get_source_id());
const std::vector<td::uint32> &f = S->get_forks();
if (d) {
auto &dd = *d;
const std::vector<CatChainBlockHeight> &dd = *d;
if (X->get_fork_id() < dd.size() && X->get_height() <= dd[X->get_fork_id()]) {
VLOG(CATCHAIN_WARNING) << this << ": has direct dep from source " << X->get_source_id() << " and prev block "
<< " has newer indirect dep";
@ -190,8 +190,8 @@ void CatChainReceivedBlockImpl::pre_deliver() {
}
}
if (S->blamed() && d) {
auto &dd = *d;
for (auto x : f) {
const std::vector<CatChainBlockHeight> &dd = *d;
for (td::uint32 x : f) {
if (x != X->get_fork_id() && dd.size() > x && dd[x] > 0) {
VLOG(CATCHAIN_WARNING) << this << ": has direct dep from source " << X->get_source_id() << " and prev block "
<< " has indirect dep to another fork of this source " << x << " " << X->get_fork_id()
@ -201,7 +201,7 @@ void CatChainReceivedBlockImpl::pre_deliver() {
return;
}
}
auto v = S->get_blamed_heights();
std::vector<CatChainBlockHeight> v = S->get_blamed_heights();
for (size_t i = 0; i < v.size() && i < dd.size(); i++) {
if (v[i] > 0 && dd[i] >= v[i]) {
@ -220,7 +220,7 @@ void CatChainReceivedBlockImpl::pre_deliver() {
if (X.is_error()) {
is_custom_ = true;
} else {
ton_api::downcast_call(*X.move_as_ok().get(), [Self = this](auto &obj) { Self->pre_deliver(obj); });
ton_api::downcast_call(*X.move_as_ok(), [Self = this](auto &obj) { Self->pre_deliver(obj); });
}
}
@ -237,7 +237,7 @@ void CatChainReceivedBlockImpl::deliver() {
state_ = bs_delivered;
VLOG(CATCHAIN_DEBUG) << this << ": delivered";
for (auto &B : rev_deps_) {
for (CatChainReceivedBlockImpl *B : rev_deps_) {
B->dep_delivered(this);
}
rev_deps_.clear();
@ -250,10 +250,10 @@ void CatChainReceivedBlockImpl::set_ill() {
return;
}
VLOG(CATCHAIN_WARNING) << this << ": got ill";
auto M = chain_->get_source(source_id_);
CatChainReceiverSource *M = chain_->get_source(source_id_);
M->blame();
state_ = bs_ill;
for (auto &B : rev_deps_) {
for (CatChainReceivedBlockImpl *B : rev_deps_) {
B->dep_ill(this);
}
}
@ -262,14 +262,14 @@ void CatChainReceivedBlockImpl::dep_ill(CatChainReceivedBlockImpl *block) {
set_ill();
}
void CatChainReceivedBlockImpl::update_deps(CatChainReceivedBlockImpl *block) {
auto &d = block->deps_;
if (d.size() > deps_.size()) {
deps_.resize(d.size(), 0);
void CatChainReceivedBlockImpl::update_vt(CatChainReceivedBlockImpl *block) {
const std::vector<CatChainBlockHeight> &d = block->vt_;
if (d.size() > vt_.size()) {
vt_.resize(d.size(), 0);
}
for (size_t i = 0; i < d.size(); i++) {
if (deps_[i] < d[i]) {
deps_[i] = d[i];
if (vt_[i] < d[i]) {
vt_[i] = d[i];
}
}
}
@ -279,7 +279,7 @@ void CatChainReceivedBlockImpl::dep_delivered(CatChainReceivedBlockImpl *block)
return;
}
CHECK(!block->is_ill());
update_deps(block);
update_vt(block);
pending_deps_--;
if (pending_deps_ == 0 && in_db_) {
schedule();
@ -332,35 +332,37 @@ void CatChainReceivedBlockImpl::find_pending_deps(std::vector<CatChainBlockHash>
if (prev_) {
prev_->find_pending_deps(vec, max_size);
}
for (auto &X : block_deps_) {
for (CatChainReceivedBlockImpl *X : block_deps_) {
X->find_pending_deps(vec, max_size);
}
}
tl_object_ptr<ton_api::catchain_block_id> CatChainReceivedBlock::block_id(CatChainReceiver *chain,
tl_object_ptr<ton_api::catchain_block> &block,
td::Slice payload) {
tl_object_ptr<ton_api::catchain_block_id> CatChainReceivedBlock::block_id(
const CatChainReceiver *chain, const tl_object_ptr<ton_api::catchain_block> &block, const td::Slice &payload) {
td::Bits256 hash = data_payload_hash(chain, block->data_, payload);
return create_tl_object<ton_api::catchain_block_id>(block->incarnation_, chain->get_source_hash(block->src_).tl(),
block->height_, sha256_bits256(payload));
block->height_, hash);
}
tl_object_ptr<ton_api::catchain_block_id> CatChainReceivedBlock::block_id(
CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block_dep> &block) {
const CatChainReceiver *chain, const tl_object_ptr<ton_api::catchain_block_dep> &block) {
return create_tl_object<ton_api::catchain_block_id>(
chain->get_incarnation(), chain->get_source_hash(block->src_).tl(), block->height_, block->data_hash_);
}
CatChainBlockHash CatChainReceivedBlock::block_hash(CatChainReceiver *chain,
tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) {
CatChainBlockHash CatChainReceivedBlock::block_hash(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block> &block,
const td::Slice &payload) {
return get_tl_object_sha_bits256(block_id(chain, block, payload));
}
CatChainBlockHash CatChainReceivedBlock::block_hash(CatChainReceiver *chain,
tl_object_ptr<ton_api::catchain_block_dep> &block) {
CatChainBlockHash CatChainReceivedBlock::block_hash(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block_dep> &block) {
return get_tl_object_sha_bits256(block_id(chain, block));
}
td::Status CatChainReceivedBlock::pre_validate_block(CatChainReceiver *chain,
tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) {
td::Status CatChainReceivedBlock::pre_validate_block(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block> &block,
const td::Slice &payload) {
CHECK(block->incarnation_ == chain->get_incarnation());
if (block->height_ <= 0) {
return td::Status::Error(ErrorCode::protoviolation, std::string("bad height ") + std::to_string(block->height_));
@ -397,7 +399,7 @@ td::Status CatChainReceivedBlock::pre_validate_block(CatChainReceiver *chain,
std::set<td::uint32> used;
used.insert(block->src_);
for (auto &X : block->data_->deps_) {
for (const auto &X : block->data_->deps_) {
if (used.find(X->src_) != used.end()) {
return td::Status::Error(ErrorCode::protoviolation, "two deps from same source");
}
@ -405,19 +407,19 @@ td::Status CatChainReceivedBlock::pre_validate_block(CatChainReceiver *chain,
}
TRY_STATUS(chain->validate_block_sync(block->data_->prev_));
for (auto &X : block->data_->deps_) {
for (const auto &X : block->data_->deps_) {
TRY_STATUS(chain->validate_block_sync(X));
}
if (payload.size() == 0) {
if (payload.empty()) {
return td::Status::Error(ErrorCode::protoviolation, "empty payload");
}
return td::Status::OK();
}
td::Status CatChainReceivedBlock::pre_validate_block(CatChainReceiver *chain,
tl_object_ptr<ton_api::catchain_block_dep> &block) {
td::Status CatChainReceivedBlock::pre_validate_block(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block_dep> &block) {
if (block->height_ < 0) {
return td::Status::Error(ErrorCode::protoviolation, std::string("bad height ") + std::to_string(block->height_));
}
@ -430,7 +432,7 @@ td::Status CatChainReceivedBlock::pre_validate_block(CatChainReceiver *chain,
return td::Status::Error(ErrorCode::protoviolation,
std::string("bad src (first block) ") + std::to_string(block->src_));
}
if (block->data_hash_ != chain->get_incarnation() || block->signature_.size() != 0) {
if (block->data_hash_ != chain->get_incarnation() || !block->signature_.empty()) {
return td::Status::Error(ErrorCode::protoviolation, std::string("bad first block"));
}
}
@ -443,9 +445,10 @@ tl_object_ptr<ton_api::catchain_block> CatChainReceivedBlockImpl::export_tl() co
CHECK(height_ > 0);
std::vector<tl_object_ptr<ton_api::catchain_block_dep>> deps;
for (auto &B : block_deps_) {
for (CatChainReceivedBlockImpl *B : block_deps_) {
deps.push_back(B->export_tl_dep());
}
CHECK(deps.size() <= chain_->opts().max_deps)
return create_tl_object<ton_api::catchain_block>(
chain_->get_incarnation(), source_id_, height_,
@ -454,35 +457,34 @@ tl_object_ptr<ton_api::catchain_block> CatChainReceivedBlockImpl::export_tl() co
}
tl_object_ptr<ton_api::catchain_block_dep> CatChainReceivedBlockImpl::export_tl_dep() const {
return create_tl_object<ton_api::catchain_block_dep>(source_id_, height_, data_hash_,
return create_tl_object<ton_api::catchain_block_dep>(source_id_, height_, data_payload_hash_,
signature_.clone_as_buffer_slice());
}
CatChainReceivedBlockImpl::CatChainReceivedBlockImpl(td::uint32 source_id, CatChainSessionId hash,
CatChainReceivedBlockImpl::CatChainReceivedBlockImpl(td::uint32 source_id, const CatChainBlockPayloadHash &hash,
CatChainReceiver *chain) {
chain_ = chain;
state_ = bs_delivered;
fork_id_ = 0;
source_id_ = source_id;
data_ = nullptr;
prev_ = nullptr;
height_ = 0;
data_hash_ = hash;
hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
chain->get_incarnation(), chain->get_incarnation(), height_, data_hash_));
data_payload_hash_ = hash;
block_id_hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
chain->get_incarnation(), chain->get_incarnation(), height_, data_payload_hash_));
}
CatChainReceivedBlockImpl::CatChainReceivedBlockImpl(tl_object_ptr<ton_api::catchain_block> block,
td::SharedSlice payload, CatChainReceiver *chain) {
chain_ = chain;
data_hash_ = sha256_bits256(payload.as_slice());
hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
block->incarnation_, chain->get_source_hash(block->src_).tl(), block->height_, data_hash_));
data_payload_hash_ = data_payload_hash(chain, block->data_, payload);
block_id_hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
block->incarnation_, chain->get_source_hash(block->src_).tl(), block->height_, data_payload_hash_));
height_ = block->height_;
source_id_ = block->src_;
CHECK(height_ <= get_max_block_height(chain->opts(), chain->get_sources_cnt()));
auto S = chain_->get_source(source_id_);
CatChainReceiverSource *S = chain_->get_source(source_id_);
S->on_new_block(this);
initialize(std::move(block), std::move(payload));
@ -491,14 +493,14 @@ CatChainReceivedBlockImpl::CatChainReceivedBlockImpl(tl_object_ptr<ton_api::catc
CatChainReceivedBlockImpl::CatChainReceivedBlockImpl(tl_object_ptr<ton_api::catchain_block_dep> block,
CatChainReceiver *chain) {
chain_ = chain;
data_hash_ = block->data_hash_;
data_payload_hash_ = block->data_hash_;
source_id_ = block->src_;
signature_ = td::SharedSlice{block->signature_.as_slice()};
hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
chain_->get_incarnation(), chain_->get_source_hash(source_id_).tl(), block->height_, data_hash_));
block_id_hash_ = get_tl_object_sha_bits256(create_tl_object<ton_api::catchain_block_id>(
chain_->get_incarnation(), chain_->get_source_hash(source_id_).tl(), block->height_, data_payload_hash_));
height_ = block->height_;
auto S = chain_->get_source(source_id_);
CatChainReceiverSource *S = chain_->get_source(source_id_);
S->on_new_block(this);
}
@ -513,9 +515,24 @@ std::unique_ptr<CatChainReceivedBlock> CatChainReceivedBlock::create(tl_object_p
}
std::unique_ptr<CatChainReceivedBlock> CatChainReceivedBlock::create_root(td::uint32 source_id,
CatChainSessionId data_hash,
CatChainSessionId session_id,
CatChainReceiver *chain) {
return std::make_unique<CatChainReceivedBlockImpl>(source_id, data_hash, chain);
return std::make_unique<CatChainReceivedBlockImpl>(source_id, session_id, chain);
}
CatChainBlockPayloadHash CatChainReceivedBlock::data_payload_hash(
const CatChainReceiver *chain, const tl_object_ptr<ton_api::catchain_block_data> &data, const td::Slice &payload) {
td::Bits256 hash = sha256_bits256(payload);
if (chain->opts().block_hash_covers_data) {
td::Bits256 data_hash = get_tl_object_sha_bits256(data);
char buf[32 * 2];
CHECK(hash.as_array().size() == 32 && data_hash.as_array().size() == 32);
std::copy(hash.as_array().begin(), hash.as_array().end(), buf);
std::copy(data_hash.as_array().begin(), data_hash.as_array().end(), buf + 32);
return sha256_bits256(td::Slice(buf, buf + 64));
} else {
return hash;
}
}
} // namespace catchain

View file

@ -30,7 +30,6 @@ namespace catchain {
class CatChainReceiver;
class CatChainReceiverSource;
class CatChainReceiverFork;
class CatChainReceivedBlock {
public:
@ -43,7 +42,7 @@ class CatChainReceivedBlock {
virtual CatChainReceivedBlock *get_prev() const = 0;
virtual CatChainBlockHash get_prev_hash() const = 0;
virtual const std::vector<CatChainBlockHeight> &get_deps() const = 0;
virtual const std::vector<CatChainBlockHeight> &get_vt() const = 0;
virtual std::vector<CatChainBlockHash> get_dep_hashes() const = 0;
virtual CatChainReceiver *get_chain() const = 0;
@ -56,6 +55,8 @@ class CatChainReceivedBlock {
virtual void find_pending_deps(std::vector<CatChainBlockHash> &vec, td::uint32 max_size) const = 0;
virtual bool has_rev_deps() const = 0;
public:
// state
virtual bool initialized() const = 0;
@ -76,20 +77,28 @@ class CatChainReceivedBlock {
td::SharedSlice payload, CatChainReceiver *chain);
static std::unique_ptr<CatChainReceivedBlock> create(tl_object_ptr<ton_api::catchain_block_dep> block,
CatChainReceiver *chain);
static std::unique_ptr<CatChainReceivedBlock> create_root(td::uint32 source_id, CatChainBlockPayloadHash data_hash,
static std::unique_ptr<CatChainReceivedBlock> create_root(td::uint32 source_id, CatChainSessionId session_id,
CatChainReceiver *chain);
static tl_object_ptr<ton_api::catchain_block_id> block_id(CatChainReceiver *chain,
tl_object_ptr<ton_api::catchain_block> &block,
td::Slice payload);
static tl_object_ptr<ton_api::catchain_block_id> block_id(CatChainReceiver *chain,
tl_object_ptr<ton_api::catchain_block_dep> &block);
static CatChainBlockHash block_hash(CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block> &block,
td::Slice payload);
static CatChainBlockHash block_hash(CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block_dep> &block);
static td::Status pre_validate_block(CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block> &block,
td::Slice payload);
static td::Status pre_validate_block(CatChainReceiver *chain, tl_object_ptr<ton_api::catchain_block_dep> &block);
static tl_object_ptr<ton_api::catchain_block_id> block_id(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block> &block,
const td::Slice &payload);
static tl_object_ptr<ton_api::catchain_block_id> block_id(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block_dep> &block);
static CatChainBlockHash block_hash(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block> &block,
const td::Slice &payload);
static CatChainBlockHash block_hash(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block_dep> &block);
static td::Status pre_validate_block(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block> &block,
const td::Slice &payload);
static td::Status pre_validate_block(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block_dep> &block);
static CatChainBlockPayloadHash data_payload_hash(const CatChainReceiver *chain,
const tl_object_ptr<ton_api::catchain_block_data> &data,
const td::Slice &payload);
virtual ~CatChainReceivedBlock() = default;
};

View file

@ -26,15 +26,14 @@ namespace catchain {
class CatChainReceiver;
class CatChainReceiverSource;
class CatChainReceiverFork;
class CatChainReceivedBlockImpl : public CatChainReceivedBlock {
class CatChainReceivedBlockImpl final : public CatChainReceivedBlock {
public:
const td::SharedSlice &get_payload() const override {
return payload_;
}
CatChainBlockHash get_hash() const override {
return hash_;
return block_id_hash_;
}
const td::SharedSlice &get_signature() const override {
return signature_;
@ -46,8 +45,8 @@ class CatChainReceivedBlockImpl : public CatChainReceivedBlock {
CatChainReceivedBlock *get_prev() const override;
CatChainBlockHash get_prev_hash() const override;
const std::vector<CatChainBlockHeight> &get_deps() const override {
return deps_;
const std::vector<CatChainBlockHeight> &get_vt() const override {
return vt_;
}
std::vector<CatChainBlockHash> get_dep_hashes() const override;
@ -69,6 +68,10 @@ class CatChainReceivedBlockImpl : public CatChainReceivedBlock {
void find_pending_deps(std::vector<CatChainBlockHash> &vec, td::uint32 max_size) const override;
bool has_rev_deps() const override {
return !rev_deps_.empty();
}
public:
bool initialized() const override {
return state_ >= bs_initialized;
@ -114,7 +117,7 @@ class CatChainReceivedBlockImpl : public CatChainReceivedBlock {
CatChainReceiver *chain);
CatChainReceivedBlockImpl(tl_object_ptr<ton_api::catchain_block_dep> block, CatChainReceiver *chain);
CatChainReceivedBlockImpl(td::uint32 source_id, CatChainSessionId hash, CatChainReceiver *chain);
CatChainReceivedBlockImpl(td::uint32 source_id, const CatChainSessionId &hash, CatChainReceiver *chain);
private:
enum State {
@ -124,31 +127,28 @@ class CatChainReceivedBlockImpl : public CatChainReceivedBlock {
bs_delivered,
} state_ = bs_none;
void update_deps(CatChainReceivedBlockImpl *block);
void update_vt(CatChainReceivedBlockImpl *block);
void add_rev_dep(CatChainReceivedBlockImpl *block);
void add_child_dep(CatChainReceivedBlockImpl *block);
void initialize_fork();
void on_ready_to_deliver();
td::uint32 fork_id_{0};
td::uint32 source_id_;
CatChainReceiver *chain_;
tl_object_ptr<ton_api::catchain_block_inner_Data> data_;
td::SharedSlice payload_;
CatChainBlockHash hash_;
CatChainBlockPayloadHash data_hash_;
CatChainBlockHash block_id_hash_{};
CatChainBlockPayloadHash data_payload_hash_{};
CatChainReceivedBlockImpl *prev_;
CatChainReceivedBlockImpl *prev_ = nullptr;
CatChainBlockHeight height_;
CatChainReceivedBlockImpl *next_ = nullptr;
std::vector<CatChainReceivedBlockImpl *> block_deps_;
std::vector<CatChainBlockHeight> deps_;
std::vector<CatChainBlockHeight> vt_;
td::SharedSlice signature_;

View file

@ -35,33 +35,33 @@ class CatChainReceiverInterface : public td::actor::Actor {
CatChainBlockHash prev, std::vector<CatChainBlockHash> deps,
std::vector<CatChainBlockHeight> vt, td::SharedSlice data) = 0;
virtual void blame(td::uint32 src_id) = 0;
virtual void on_custom_message(PublicKeyHash src, td::BufferSlice data) = 0;
virtual void on_custom_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
virtual void on_broadcast(PublicKeyHash src, td::BufferSlice data) = 0;
virtual void on_custom_query(const PublicKeyHash &src, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) = 0;
virtual void on_broadcast(const PublicKeyHash &src, td::BufferSlice data) = 0;
virtual void start() = 0;
virtual ~Callback() = default;
};
virtual void add_block(td::BufferSlice payload, std::vector<CatChainBlockHash> deps) = 0;
virtual void debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height,
std::vector<CatChainBlockHash> deps) = 0;
virtual void blame_node(td::uint32 idx) = 0;
virtual void send_fec_broadcast(td::BufferSlice data) = 0;
virtual void send_custom_query_data(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
virtual void send_custom_query_data(const PublicKeyHash &dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice query) = 0;
virtual void send_custom_query_data_via(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice query, td::uint64 max_answer_size,
virtual void send_custom_query_data_via(const PublicKeyHash &dst, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice query, td::uint64 max_answer_size,
td::actor::ActorId<adnl::AdnlSenderInterface> via) = 0;
virtual void send_custom_message_data(PublicKeyHash dst, td::BufferSlice query) = 0;
virtual void send_custom_message_data(const PublicKeyHash &dst, td::BufferSlice query) = 0;
virtual void destroy() = 0;
static td::actor::ActorOwn<CatChainReceiverInterface> create(
std::unique_ptr<Callback> callback, CatChainOptions opts, td::actor::ActorId<keyring::Keyring> keyring,
std::unique_ptr<Callback> callback, const CatChainOptions &opts, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<overlay::Overlays> overlay_manager,
std::vector<CatChainNode> ids, PublicKeyHash local_id, CatChainSessionId unique_hash, std::string db_root,
std::string db_suffix, bool allow_unsafe_self_blocks_resync);
const std::vector<CatChainNode> &ids, const PublicKeyHash &local_id, const CatChainSessionId &unique_hash,
std::string db_root, std::string db_suffix, bool allow_unsafe_self_blocks_resync);
virtual ~CatChainReceiverInterface() = default;
~CatChainReceiverInterface() override = default;
};
} // namespace catchain

View file

@ -24,10 +24,10 @@ namespace ton {
namespace catchain {
td::uint32 CatChainReceiverSourceImpl::add_fork() {
if (fork_ids_.size() > 0) {
if (!fork_ids_.empty()) {
blame();
}
auto F = chain_->add_fork();
td::uint32 F = chain_->add_fork();
CHECK(F > 0);
fork_ids_.push_back(F);
@ -60,7 +60,7 @@ td::Result<std::unique_ptr<CatChainReceiverSource>> CatChainReceiverSource::crea
void CatChainReceiverSourceImpl::blame(td::uint32 fork, CatChainBlockHeight height) {
blame();
if (blamed_heights_.size() > 0) {
if (!blamed_heights_.empty()) {
if (blamed_heights_.size() <= fork) {
blamed_heights_.resize(fork + 1, 0);
}
@ -130,19 +130,6 @@ void CatChainReceiverSourceImpl::block_delivered(CatChainBlockHeight height) {
}
}
td::Status CatChainReceiverSourceImpl::validate_dep_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) {
auto S = std::move(dep->signature_);
auto str = serialize_tl_object(dep, true);
dep->signature_ = std::move(S);
auto R = encryptor_sync_->check_signature(str.as_slice(), dep->signature_.as_slice());
if (R.is_error()) {
return R.move_as_error();
}
return td::Status::OK();
}
void CatChainReceiverSourceImpl::on_new_block(CatChainReceivedBlock *block) {
if (fork_is_found()) {
return;
@ -165,7 +152,7 @@ void CatChainReceiverSourceImpl::on_new_block(CatChainReceivedBlock *block) {
blocks_[block->get_height()] = block;
}
void CatChainReceiverSourceImpl::on_found_fork_proof(td::Slice proof) {
void CatChainReceiverSourceImpl::on_found_fork_proof(const td::Slice &proof) {
if (!fork_is_found()) {
fetch_tl_object<ton_api::catchain_block_data_fork>(proof, true).ensure();
fork_proof_ = td::SharedSlice{proof};

View file

@ -56,9 +56,8 @@ class CatChainReceiverSource {
virtual bool has_unreceived() const = 0;
virtual bool has_undelivered() const = 0;
virtual td::Status validate_dep_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) = 0;
virtual void on_new_block(CatChainReceivedBlock *block) = 0;
virtual void on_found_fork_proof(td::Slice fork) = 0;
virtual void on_found_fork_proof(const td::Slice &fork) = 0;
virtual td::BufferSlice fork_proof() const = 0;
virtual bool fork_is_found() const = 0;

View file

@ -23,6 +23,7 @@
#include "catchain-receiver-source.h"
#include "catchain-receiver.h"
#include "catchain-received-block.h"
#include <queue>
namespace ton {
@ -82,7 +83,7 @@ class CatChainReceiverSourceImpl : public CatChainReceiverSource {
if (blamed()) {
return true;
}
if (!blocks_.size()) {
if (blocks_.empty()) {
return false;
}
CHECK(blocks_.rbegin()->second->get_height() >= received_height_);
@ -93,9 +94,8 @@ class CatChainReceiverSourceImpl : public CatChainReceiverSource {
}
CatChainReceivedBlock *get_block(CatChainBlockHeight height) const override;
td::Status validate_dep_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) override;
void on_new_block(CatChainReceivedBlock *block) override;
void on_found_fork_proof(td::Slice proof) override;
void on_found_fork_proof(const td::Slice &proof) override;
bool fork_is_found() const override {
return !fork_proof_.empty();
}
@ -103,7 +103,7 @@ class CatChainReceiverSourceImpl : public CatChainReceiverSource {
if (!fork_proof_.empty()) {
return fork_proof_.clone_as_buffer_slice();
} else {
return td::BufferSlice();
return {};
}
}

View file

@ -17,6 +17,7 @@
Copyright 2017-2020 Telegram Systems LLP
*/
#include <set>
#include <utility>
#include "td/actor/PromiseFuture.h"
#include "td/utils/Random.h"
#include "td/db/RocksDb.h"
@ -30,6 +31,25 @@ namespace ton {
namespace catchain {
static const td::uint32 MAX_NEIGHBOURS = 5;
static const double EXPECTED_UNSAFE_INITIAL_SYNC_DURATION = 300.0;
static const double EXPECTED_INITIAL_SYNC_DURATION = 5.0;
static const td::uint32 OVERLAY_MAX_ALLOWED_PACKET_SIZE = 16 * 1024 * 1024;
static const double NEIGHBOURS_ROTATE_INTERVAL_MIN = 60;
static const double NEIGHBOURS_ROTATE_INTERVAL_MAX = 120;
static const td::uint32 MAX_QUERY_BLOCKS = 100;
static const td::uint32 MAX_QUERY_HEIGHT = 100;
static const td::uint32 GET_DIFFERENCE_MAX_SEND = 100;
static const double GET_DIFFERENCE_TIMEOUT = 5.0;
static const double GET_BLOCK_TIMEOUT = 2.0;
static const td::uint32 MAX_PENDING_DEPS = 16;
static const double EXPECTED_INITIAL_SYNC_DURATION_WITH_UNPROCESSED = 60.0;
static const double SYNC_INTERVAL_MIN = 0.1;
static const double SYNC_INTERVAL_MAX = 0.2;
static const td::uint32 SYNC_ITERATIONS = 3;
static const double DESTROY_DB_DELAY = 1.0;
static const td::uint32 DESTROY_DB_MAX_ATTEMPTS = 10;
PublicKeyHash CatChainReceiverImpl::get_source_hash(td::uint32 source_id) const {
CHECK(source_id < sources_.size());
return sources_[source_id]->get_hash();
@ -45,18 +65,19 @@ void CatChainReceiverImpl::deliver_block(CatChainReceivedBlock *block) {
<< " custom=" << block->is_custom();
callback_->new_block(block->get_source_id(), block->get_fork_id(), block->get_hash(), block->get_height(),
block->get_height() == 1 ? CatChainBlockHash::zero() : block->get_prev_hash(),
block->get_dep_hashes(), block->get_deps(),
block->get_dep_hashes(), block->get_vt(),
block->is_custom() ? block->get_payload().clone() : td::SharedSlice());
std::vector<adnl::AdnlNodeIdShort> v;
for (auto it : neighbours_) {
auto S = get_source(it);
for (td::uint32 it : neighbours_) {
CatChainReceiverSource *S = get_source(it);
v.push_back(S->get_adnl_id());
}
auto update = create_tl_object<ton_api::catchain_blockUpdate>(block->export_tl());
auto D = serialize_tl_object(update, true, block->get_payload().as_slice());
td::BufferSlice D = serialize_tl_object(update, true, block->get_payload().as_slice());
CHECK(D.size() <= opts_.max_serialized_block_size);
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_multiple_messages, std::move(v),
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(D));
@ -64,8 +85,8 @@ void CatChainReceiverImpl::deliver_block(CatChainReceivedBlock *block) {
void CatChainReceiverImpl::receive_block(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::catchain_block> block,
td::BufferSlice payload) {
auto id = CatChainReceivedBlock::block_hash(this, block, payload);
auto B = get_block(id);
CatChainBlockHash id = CatChainReceivedBlock::block_hash(this, block, payload);
CatChainReceivedBlock *B = get_block(id);
if (B && B->initialized()) {
return;
}
@ -76,7 +97,27 @@ void CatChainReceiverImpl::receive_block(adnl::AdnlNodeIdShort src, tl_object_pt
return;
}
auto S = validate_block_sync(block, payload.as_slice());
td::uint64 max_block_height = get_max_block_height(opts_, sources_.size());
if ((td::uint32)block->height_ > max_block_height) {
VLOG(CATCHAIN_WARNING) << this << ": received too many blocks from " << src
<< " (limit=" << max_block_height << ")";
return;
}
td::uint32 src_id = block->src_;
if (src_id >= get_sources_cnt()) {
VLOG(CATCHAIN_WARNING) << this << ": received broken block from " << src << ": bad src " << block->src_;
return;
}
CatChainReceiverSource *source = get_source(src_id);
if (source->fork_is_found()) {
if (B == nullptr || !B->has_rev_deps()) {
VLOG(CATCHAIN_WARNING) << this << ": dropping block from source " << src_id << ": source has a fork";
return;
}
}
td::Status S = validate_block_sync(block, payload.as_slice());
if (S.is_error()) {
VLOG(CATCHAIN_WARNING) << this << ": received broken block from " << src << ": " << S.move_as_error();
@ -89,11 +130,11 @@ void CatChainReceiverImpl::receive_block(adnl::AdnlNodeIdShort src, tl_object_pt
<< " (unsafe=" << allow_unsafe_self_blocks_resync_ << ")";
} else {
LOG(ERROR) << this << ": received unknown SELF block from " << src << ". UPDATING LOCAL DATABASE. UNSAFE";
initial_sync_complete_at_ = td::Timestamp::in(300.0);
initial_sync_complete_at_ = td::Timestamp::in(EXPECTED_UNSAFE_INITIAL_SYNC_DURATION);
}
}
auto raw_data = serialize_tl_object(block, true, payload.as_slice());
td::BufferSlice raw_data = serialize_tl_object(block, true, payload.as_slice());
create_block(std::move(block), td::SharedSlice{payload.as_slice()});
if (!opts_.debug_disable_db) {
@ -104,6 +145,11 @@ void CatChainReceiverImpl::receive_block(adnl::AdnlNodeIdShort src, tl_object_pt
}
void CatChainReceiverImpl::receive_block_answer(adnl::AdnlNodeIdShort src, td::BufferSlice data) {
if (data.size() > opts_.max_serialized_block_size) {
VLOG(CATCHAIN_INFO) << this << ": received bad block result " << src << ": too big (size="
<< data.size() << ", limit=" << opts_.max_serialized_block_size << ")";
return;
}
auto F = fetch_tl_prefix<ton_api::catchain_BlockResult>(data, true);
if (F.is_error()) {
VLOG(CATCHAIN_INFO) << this << ": received bad block result: " << F.move_as_error();
@ -111,7 +157,7 @@ void CatChainReceiverImpl::receive_block_answer(adnl::AdnlNodeIdShort src, td::B
}
auto f = F.move_as_ok();
ton_api::downcast_call(
*f.get(),
*f,
td::overloaded(
[&](ton_api::catchain_blockNotFound &r) { VLOG(CATCHAIN_INFO) << this << ": catchain block not found"; },
[&](ton_api::catchain_blockResult &r) { receive_block(src, std::move(r.block_), std::move(data)); }));
@ -129,6 +175,11 @@ void CatChainReceiverImpl::receive_message_from_overlay(adnl::AdnlNodeIdShort sr
VLOG(CATCHAIN_INFO) << this << ": dropping block update from blamed source " << src;
return;
}*/
if (data.size() > opts_.max_serialized_block_size) {
VLOG(CATCHAIN_WARNING) << this << ": dropping broken block from " << src << ": too big (size="
<< data.size() << ", limit=" << opts_.max_serialized_block_size << ")";
return;
}
auto R = fetch_tl_prefix<ton_api::catchain_blockUpdate>(data, true);
if (R.is_error()) {
VLOG(CATCHAIN_WARNING) << this << ": dropping broken block from " << src << ": " << R.move_as_error();
@ -139,14 +190,14 @@ void CatChainReceiverImpl::receive_message_from_overlay(adnl::AdnlNodeIdShort sr
receive_block(src, std::move(U->block_), std::move(data));
}
void CatChainReceiverImpl::receive_broadcast_from_overlay(PublicKeyHash src, td::BufferSlice data) {
void CatChainReceiverImpl::receive_broadcast_from_overlay(const PublicKeyHash &src, td::BufferSlice data) {
if (!read_db_) {
return;
}
callback_->on_broadcast(src, std::move(data));
}
/*void CatChainReceiverImpl::send_block(PublicKeyHash src, tl_object_ptr<ton_api::catchain_block> block,
/*void CatChainReceiverImpl::send_block(const PublicKeyHash &src, tl_object_ptr<ton_api::catchain_block> block,
td::BufferSlice payload) {
CHECK(read_db_);
CHECK(src == local_id_);
@ -164,7 +215,7 @@ CatChainReceivedBlock *CatChainReceiverImpl::create_block(tl_object_ptr<ton_api:
if (block->height_ == 0) {
return root_block_;
}
auto hash = CatChainReceivedBlock::block_hash(this, block, payload.as_slice());
CatChainBlockHash hash = CatChainReceivedBlock::block_hash(this, block, payload.as_slice());
auto it = blocks_.find(hash);
if (it != blocks_.end()) {
@ -173,9 +224,8 @@ CatChainReceivedBlock *CatChainReceiverImpl::create_block(tl_object_ptr<ton_api:
}
return it->second.get();
} else {
blocks_.emplace(hash, CatChainReceivedBlock::create(std::move(block), std::move(payload), this));
it = blocks_.find(hash);
return it->second.get();
auto r = blocks_.emplace(hash, CatChainReceivedBlock::create(std::move(block), std::move(payload), this));
return r.first->second.get();
}
}
@ -183,7 +233,7 @@ CatChainReceivedBlock *CatChainReceiverImpl::create_block(tl_object_ptr<ton_api:
if (block->height_ == 0) {
return root_block_;
}
auto hash = CatChainReceivedBlock::block_hash(this, block);
CatChainBlockHash hash = CatChainReceivedBlock::block_hash(this, block);
auto it = blocks_.find(hash);
if (it != blocks_.end()) {
return it->second.get();
@ -194,20 +244,20 @@ CatChainReceivedBlock *CatChainReceiverImpl::create_block(tl_object_ptr<ton_api:
}
}
td::Status CatChainReceiverImpl::validate_block_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) {
td::Status CatChainReceiverImpl::validate_block_sync(const tl_object_ptr<ton_api::catchain_block_dep> &dep) const {
TRY_STATUS_PREFIX(CatChainReceivedBlock::pre_validate_block(this, dep), "failed to validate block: ");
if (dep->height_ > 0) {
auto id = CatChainReceivedBlock::block_id(this, dep);
auto B = serialize_tl_object(id, true);
auto block = get_block(get_tl_object_sha_bits256(id));
td::BufferSlice B = serialize_tl_object(id, true);
CatChainReceivedBlock *block = get_block(get_tl_object_sha_bits256(id));
if (block) {
return td::Status::OK();
}
auto S = get_source_by_hash(PublicKeyHash{id->src_});
CatChainReceiverSource *S = get_source_by_hash(PublicKeyHash{id->src_});
CHECK(S != nullptr);
auto E = S->get_encryptor_sync();
Encryptor *E = S->get_encryptor_sync();
CHECK(E != nullptr);
return E->check_signature(B.as_slice(), dep->signature_.as_slice());
} else {
@ -215,17 +265,18 @@ td::Status CatChainReceiverImpl::validate_block_sync(tl_object_ptr<ton_api::catc
}
}
td::Status CatChainReceiverImpl::validate_block_sync(tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) {
td::Status CatChainReceiverImpl::validate_block_sync(const tl_object_ptr<ton_api::catchain_block> &block,
const td::Slice &payload) const {
//LOG(INFO) << ton_api::to_string(block);
TRY_STATUS_PREFIX(CatChainReceivedBlock::pre_validate_block(this, block, payload), "failed to validate block: ");
if (block->height_ > 0) {
auto id = CatChainReceivedBlock::block_id(this, block, payload);
auto B = serialize_tl_object(id, true);
td::BufferSlice B = serialize_tl_object(id, true);
auto S = get_source_by_hash(PublicKeyHash{id->src_});
CatChainReceiverSource *S = get_source_by_hash(PublicKeyHash{id->src_});
CHECK(S != nullptr);
auto E = S->get_encryptor_sync();
Encryptor *E = S->get_encryptor_sync();
CHECK(E != nullptr);
return E->check_signature(B.as_slice(), block->signature_.as_slice());
} else {
@ -235,7 +286,7 @@ td::Status CatChainReceiverImpl::validate_block_sync(tl_object_ptr<ton_api::catc
void CatChainReceiverImpl::run_scheduler() {
while (!to_run_.empty()) {
auto B = to_run_.front();
CatChainReceivedBlock *B = to_run_.front();
to_run_.pop_front();
B->run();
@ -265,7 +316,7 @@ void CatChainReceiverImpl::add_block_cont_3(tl_object_ptr<ton_api::catchain_bloc
}
active_send_ = false;
if (pending_blocks_.size() > 0) {
if (!pending_blocks_.empty()) {
auto B = std::move(pending_blocks_.front());
pending_blocks_.pop_front();
add_block(std::move(B->payload_), std::move(B->deps_));
@ -278,9 +329,9 @@ void CatChainReceiverImpl::add_block_cont_2(tl_object_ptr<ton_api::catchain_bloc
return;
}
auto id = CatChainReceivedBlock::block_hash(this, block, payload);
CatChainBlockHash id = CatChainReceivedBlock::block_hash(this, block, payload);
td::BufferSlice raw_data{32};
td::BufferSlice raw_data{id.as_array().size()};
raw_data.as_slice().copy_from(as_slice(id));
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), block = std::move(block),
@ -298,9 +349,9 @@ void CatChainReceiverImpl::add_block_cont(tl_object_ptr<ton_api::catchain_block>
add_block_cont_2(std::move(block), std::move(payload));
return;
}
auto id = CatChainReceivedBlock::block_hash(this, block, payload.as_slice());
CatChainBlockHash id = CatChainReceivedBlock::block_hash(this, block, payload.as_slice());
auto raw_data = serialize_tl_object(block, true, payload.as_slice());
td::BufferSlice raw_data = serialize_tl_object(block, true, payload.as_slice());
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), block = std::move(block),
payload = std::move(payload)](td::Result<td::Unit> R) mutable {
@ -319,7 +370,7 @@ void CatChainReceiverImpl::add_block(td::BufferSlice payload, std::vector<CatCha
}
active_send_ = true;
auto S = get_source_by_hash(local_id_);
CatChainReceiverSource *S = get_source_by_hash(local_id_);
CHECK(S != nullptr);
CHECK(S->get_id() == local_idx_);
if (!intentional_fork_) {
@ -331,7 +382,7 @@ void CatChainReceiverImpl::add_block(td::BufferSlice payload, std::vector<CatCha
std::vector<tl_object_ptr<ton_api::catchain_block_dep>> deps_arr;
deps_arr.resize(deps.size());
for (size_t i = 0; i < deps.size(); i++) {
auto B = get_block(deps[i]);
CatChainReceivedBlock *B = get_block(deps[i]);
LOG_CHECK(B != nullptr) << this << ": cannot find block with hash " << deps[i];
if (!intentional_fork_) {
CHECK(B->get_source_id() != local_idx_);
@ -339,13 +390,13 @@ void CatChainReceiverImpl::add_block(td::BufferSlice payload, std::vector<CatCha
deps_arr[i] = B->export_tl_dep();
}
auto height = prev->height_ + 1;
int height = prev->height_ + 1;
auto block_data = create_tl_object<ton_api::catchain_block_data>(std::move(prev), std::move(deps_arr));
auto block = create_tl_object<ton_api::catchain_block>(incarnation_, local_idx_, height, std::move(block_data),
td::BufferSlice());
auto id = CatChainReceivedBlock::block_id(this, block, payload);
auto id_s = serialize_tl_object(id, true);
td::BufferSlice id_s = serialize_tl_object(id, true);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), print_id = print_id(), block = std::move(block),
payload = std::move(payload)](td::Result<td::BufferSlice> R) mutable {
@ -362,24 +413,24 @@ void CatChainReceiverImpl::add_block(td::BufferSlice payload, std::vector<CatCha
void CatChainReceiverImpl::debug_add_fork_cont(tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload) {
validate_block_sync(block, payload.as_slice()).ensure();
auto B = create_block(std::move(block), td::SharedSlice{payload.as_slice()});
CatChainReceivedBlock *B = create_block(std::move(block), td::SharedSlice{payload.as_slice()});
B->written();
run_scheduler();
CHECK(B->delivered());
active_send_ = false;
if (pending_blocks_.size() > 0) {
auto B = std::move(pending_blocks_.front());
if (!pending_blocks_.empty()) {
auto pending_block = std::move(pending_blocks_.front());
pending_blocks_.pop_front();
add_block(std::move(B->payload_), std::move(B->deps_));
add_block(std::move(pending_block->payload_), std::move(pending_block->deps_));
}
}
void CatChainReceiverImpl::debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height,
std::vector<CatChainBlockHash> deps) {
intentional_fork_ = true;
auto S = get_source_by_hash(local_id_);
CatChainReceiverSource *S = get_source_by_hash(local_id_);
CHECK(S != nullptr);
CHECK(S->get_id() == local_idx_);
@ -399,7 +450,7 @@ void CatChainReceiverImpl::debug_add_fork(td::BufferSlice payload, CatChainBlock
std::vector<tl_object_ptr<ton_api::catchain_block_dep>> deps_arr;
deps_arr.resize(deps.size());
for (size_t i = 0; i < deps.size(); i++) {
auto B = get_block(deps[i]);
CatChainReceivedBlock *B = get_block(deps[i]);
LOG_CHECK(B != nullptr) << this << ": cannot find block with hash " << deps[i];
CHECK(B->get_source_id() != local_idx_);
deps_arr[i] = B->export_tl_dep();
@ -410,7 +461,7 @@ void CatChainReceiverImpl::debug_add_fork(td::BufferSlice payload, CatChainBlock
td::BufferSlice());
auto id = CatChainReceivedBlock::block_id(this, block, payload);
auto id_s = serialize_tl_object(id, true);
td::BufferSlice id_s = serialize_tl_object(id, true);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), print_id = print_id(), block = std::move(block),
payload = std::move(payload)](td::Result<td::BufferSlice> R) mutable {
@ -425,29 +476,33 @@ void CatChainReceiverImpl::debug_add_fork(td::BufferSlice payload, CatChainBlock
td::actor::send_closure_later(keyring_, &keyring::Keyring::sign_message, local_id_, std::move(id_s), std::move(P));
}
CatChainReceiverImpl::CatChainReceiverImpl(std::unique_ptr<Callback> callback, CatChainOptions opts,
CatChainReceiverImpl::CatChainReceiverImpl(std::unique_ptr<Callback> callback,
const CatChainOptions &opts,
td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<overlay::Overlays> overlay_manager,
std::vector<CatChainNode> ids, PublicKeyHash local_id,
CatChainSessionId unique_hash, std::string db_root, std::string db_suffix,
const std::vector<CatChainNode> &ids,
const PublicKeyHash &local_id,
const CatChainSessionId &unique_hash,
std::string db_root,
std::string db_suffix,
bool allow_unsafe_self_blocks_resync)
: callback_(std::move(callback))
, opts_(std::move(opts))
, keyring_(keyring)
, adnl_(adnl)
, overlay_manager_(overlay_manager)
, opts_(opts)
, keyring_(std::move(keyring))
, adnl_(std::move(adnl))
, overlay_manager_(std::move(overlay_manager))
, local_id_(local_id)
, db_root_(db_root)
, db_suffix_(db_suffix)
, db_root_(std::move(db_root))
, db_suffix_(std::move(db_suffix))
, allow_unsafe_self_blocks_resync_(allow_unsafe_self_blocks_resync) {
std::vector<td::Bits256> short_ids;
local_idx_ = static_cast<td::uint32>(ids.size());
for (auto &id : ids) {
td::uint32 seq = static_cast<td::uint32>(sources_.size());
for (const CatChainNode &id : ids) {
auto seq = static_cast<td::uint32>(sources_.size());
auto R = CatChainReceiverSource::create(this, id.pub_key, id.adnl_id, seq);
auto S = R.move_as_ok();
auto h = id.pub_key.compute_short_id();
PublicKeyHash h = id.pub_key.compute_short_id();
short_ids.push_back(h.bits256_value());
sources_hashes_[h] = seq;
sources_adnl_addrs_[id.adnl_id] = seq;
@ -477,12 +532,13 @@ CatChainReceiverImpl::CatChainReceiverImpl(std::unique_ptr<Callback> callback, C
void CatChainReceiverImpl::start_up() {
std::vector<adnl::AdnlNodeIdShort> ids;
ids.reserve(get_sources_cnt());
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
ids.push_back(get_source(i)->get_adnl_id());
}
std::map<PublicKeyHash, td::uint32> root_keys;
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
root_keys.emplace(get_source(i)->get_hash(), 16 << 20);
root_keys.emplace(get_source(i)->get_hash(), OVERLAY_MAX_ALLOWED_PACKET_SIZE);
}
td::actor::send_closure(overlay_manager_, &overlay::Overlays::create_private_overlay,
get_source(local_idx_)->get_adnl_id(), overlay_full_id_.clone(), std::move(ids),
@ -498,13 +554,13 @@ void CatChainReceiverImpl::start_up() {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<DbType::GetResult> R) {
R.ensure();
auto g = R.move_as_ok();
DbType::GetResult g = R.move_as_ok();
if (g.status == td::KeyValue::GetStatus::NotFound) {
td::actor::send_closure(SelfId, &CatChainReceiverImpl::read_db);
} else {
auto B = std::move(g.value);
CHECK(B.size() == 32);
td::BufferSlice B = std::move(g.value);
CatChainBlockHash x;
CHECK(B.size() == x.as_array().size());
as_slice(x).copy_from(B.as_slice());
td::actor::send_closure(SelfId, &CatChainReceiverImpl::read_db_from, x);
}
@ -527,7 +583,7 @@ void CatChainReceiverImpl::read_db_from(CatChainBlockHash id) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id](td::Result<DbType::GetResult> R) {
R.ensure();
auto g = R.move_as_ok();
DbType::GetResult g = R.move_as_ok();
CHECK(g.status == td::KeyValue::GetStatus::Ok);
td::actor::send_closure(SelfId, &CatChainReceiverImpl::read_block_from_db, id, std::move(g.value));
@ -543,12 +599,12 @@ void CatChainReceiverImpl::read_block_from_db(CatChainBlockHash id, td::BufferSl
F.ensure();
auto block = F.move_as_ok();
auto payload = std::move(data);
td::BufferSlice payload = std::move(data);
auto block_id = CatChainReceivedBlock::block_hash(this, block, payload);
CatChainBlockHash block_id = CatChainReceivedBlock::block_hash(this, block, payload);
CHECK(block_id == id);
auto B = get_block(id);
CatChainReceivedBlock *B = get_block(id);
if (B && B->initialized()) {
CHECK(B->in_db());
if (!pending_in_db_) {
@ -557,7 +613,7 @@ void CatChainReceiverImpl::read_block_from_db(CatChainBlockHash id, td::BufferSl
return;
}
auto source = get_source(block->src_);
CatChainReceiverSource *source = get_source(block->src_);
CHECK(source != nullptr);
CHECK(block->incarnation_ == incarnation_);
@ -565,18 +621,18 @@ void CatChainReceiverImpl::read_block_from_db(CatChainBlockHash id, td::BufferSl
validate_block_sync(block, payload).ensure();
B = create_block(std::move(block), td::SharedSlice{payload.as_slice()});
B->written();
CHECK(B);
B->written();
auto deps = B->get_dep_hashes();
std::vector<CatChainBlockHash> deps = B->get_dep_hashes();
deps.push_back(B->get_prev_hash());
for (auto &dep : deps) {
auto dep_block = get_block(dep);
for (const CatChainBlockHash &dep : deps) {
CatChainReceivedBlock *dep_block = get_block(dep);
if (!dep_block || !dep_block->initialized()) {
pending_in_db_++;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), dep](td::Result<DbType::GetResult> R) {
R.ensure();
auto g = R.move_as_ok();
DbType::GetResult g = R.move_as_ok();
CHECK(g.status == td::KeyValue::GetStatus::Ok);
td::actor::send_closure(SelfId, &CatChainReceiverImpl::read_block_from_db, dep, std::move(g.value));
@ -601,26 +657,28 @@ void CatChainReceiverImpl::read_db() {
read_db_ = true;
next_rotate_ = td::Timestamp::in(60 + td::Random::fast(0, 60));
next_sync_ = td::Timestamp::in(0.001 * td::Random::fast(0, 60));
initial_sync_complete_at_ = td::Timestamp::in(allow_unsafe_self_blocks_resync_ ? 300.0 : 5.0);
next_rotate_ = td::Timestamp::in(td::Random::fast(NEIGHBOURS_ROTATE_INTERVAL_MIN, NEIGHBOURS_ROTATE_INTERVAL_MAX));
next_sync_ = td::Timestamp::in(
0.001 * td::Random::fast(NEIGHBOURS_ROTATE_INTERVAL_MIN, NEIGHBOURS_ROTATE_INTERVAL_MAX));
initial_sync_complete_at_ = td::Timestamp::in(
allow_unsafe_self_blocks_resync_ ? EXPECTED_UNSAFE_INITIAL_SYNC_DURATION : EXPECTED_INITIAL_SYNC_DURATION);
alarm_timestamp().relax(next_rotate_);
alarm_timestamp().relax(next_sync_);
alarm_timestamp().relax(initial_sync_complete_at_);
}
td::actor::ActorOwn<CatChainReceiverInterface> CatChainReceiverInterface::create(
std::unique_ptr<Callback> callback, CatChainOptions opts, td::actor::ActorId<keyring::Keyring> keyring,
std::unique_ptr<Callback> callback, const CatChainOptions &opts, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<overlay::Overlays> overlay_manager,
std::vector<CatChainNode> ids, PublicKeyHash local_id, CatChainSessionId unique_hash, std::string db_root,
std::string db_suffix, bool allow_unsafe_self_blocks_resync) {
const std::vector<CatChainNode> &ids, const PublicKeyHash &local_id, const CatChainSessionId &unique_hash,
std::string db_root, std::string db_suffix, bool allow_unsafe_self_blocks_resync) {
auto A = td::actor::create_actor<CatChainReceiverImpl>(
"catchainreceiver", std::move(callback), std::move(opts), keyring, adnl, overlay_manager, std::move(ids),
local_id, unique_hash, db_root, db_suffix, allow_unsafe_self_blocks_resync);
"catchainreceiver", std::move(callback), opts, std::move(keyring), std::move(adnl), std::move(overlay_manager),
ids, local_id, unique_hash, std::move(db_root), std::move(db_suffix), allow_unsafe_self_blocks_resync);
return std::move(A);
}
CatChainReceiverSource *CatChainReceiverImpl::get_source_by_hash(PublicKeyHash source_hash) const {
CatChainReceiverSource *CatChainReceiverImpl::get_source_by_hash(const PublicKeyHash &source_hash) const {
auto it = sources_hashes_.find(source_hash);
if (it == sources_hashes_.end()) {
return nullptr;
@ -650,10 +708,10 @@ void CatChainReceiverImpl::receive_query_from_overlay(adnl::AdnlNodeIdShort src,
return;
}
auto f = F.move_as_ok();
ton_api::downcast_call(*f.get(), [&](auto &obj) { this->process_query(src, obj, std::move(promise)); });
ton_api::downcast_call(*f, [&](auto &obj) { this->process_query(src, std::move(obj), std::move(promise)); });
}
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlock &query,
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlock query,
td::Promise<td::BufferSlice> promise) {
auto it = blocks_.find(query.block_);
if (it == blocks_.end() || it->second->get_height() == 0 || !it->second->initialized()) {
@ -664,19 +722,20 @@ void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::cat
}
}
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlocks &query,
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlocks query,
td::Promise<td::BufferSlice> promise) {
if (query.blocks_.size() > 100) {
if (query.blocks_.size() > MAX_QUERY_BLOCKS) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "too many blocks"));
return;
}
td::int32 cnt = 0;
for (auto &b : query.blocks_) {
for (const CatChainBlockHash &b : query.blocks_) {
auto it = blocks_.find(b);
if (it != blocks_.end() && it->second->get_height() > 0) {
auto block = create_tl_object<ton_api::catchain_blockUpdate>(it->second->export_tl());
CHECK(it->second->get_payload().size() > 0);
auto B = serialize_tl_object(block, true, it->second->get_payload().clone());
CHECK(!it->second->get_payload().empty());
td::BufferSlice B = serialize_tl_object(block, true, it->second->get_payload().clone());
CHECK(B.size() <= opts_.max_serialized_block_size);
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_message, src,
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(B));
cnt++;
@ -685,19 +744,19 @@ void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::cat
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_sent>(cnt), true));
}
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlockHistory &query,
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlockHistory query,
td::Promise<td::BufferSlice> promise) {
auto h = query.height_;
int64_t h = query.height_;
if (h <= 0) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "not-positive height"));
return;
}
if (h > 100) {
h = 100;
if (h > MAX_QUERY_HEIGHT) {
h = MAX_QUERY_HEIGHT;
}
std::set<CatChainBlockHash> s{query.stop_if_.begin(), query.stop_if_.end()};
auto B = get_block(query.block_);
CatChainReceivedBlock *B = get_block(query.block_);
if (B == nullptr) {
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_sent>(0), true));
return;
@ -711,8 +770,9 @@ void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::cat
break;
}
auto block = create_tl_object<ton_api::catchain_blockUpdate>(B->export_tl());
CHECK(B->get_payload().size() > 0);
auto BB = serialize_tl_object(block, true, B->get_payload().as_slice());
CHECK(!B->get_payload().empty());
td::BufferSlice BB = serialize_tl_object(block, true, B->get_payload().as_slice());
CHECK(BB.size() <= opts_.max_serialized_block_size);
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_message, src,
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(BB));
B = B->get_prev();
@ -721,7 +781,7 @@ void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::cat
promise.set_value(serialize_tl_object(create_tl_object<ton_api::catchain_sent>(cnt), true));
}
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getDifference &query,
void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getDifference query,
td::Promise<td::BufferSlice> promise) {
auto &vt = query.rt_;
if (vt.size() != get_sources_cnt()) {
@ -731,7 +791,7 @@ void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::cat
}
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
if (vt[i] >= 0) {
auto S = get_source(i);
CatChainReceiverSource *S = get_source(i);
if (S->fork_is_found()) {
auto obj = fetch_tl_object<ton_api::catchain_block_data_fork>(S->fork_proof(), true);
obj.ensure();
@ -744,26 +804,21 @@ void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::cat
}
std::vector<td::int32> my_vt(get_sources_cnt());
td::uint64 total = 0;
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
if (vt[i] >= 0) {
auto x = static_cast<CatChainBlockHeight>(vt[i]);
auto S = get_source(i);
if (S->delivered_height() > x) {
total += S->delivered_height() - x;
}
my_vt[i] = S->delivered_height();
CatChainReceiverSource *S = get_source(i);
my_vt[i] = static_cast<td::int32>(S->delivered_height());
} else {
my_vt[i] = -1;
}
}
const td::uint32 max_send = 100;
const td::uint32 max_send = GET_DIFFERENCE_MAX_SEND;
td::int32 l = 0;
td::int32 r = max_send + 1;
while (r - l > 1) {
td::int32 x = (r + l) / 2;
td::int32 left = 0;
td::int32 right = max_send + 1;
while (right - left > 1) {
td::int32 x = (right + left) / 2;
td::uint64 sum = 0;
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
if (vt[i] >= 0 && my_vt[i] > vt[i]) {
@ -771,23 +826,23 @@ void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::cat
}
}
if (sum > max_send) {
r = x;
right = x;
} else {
l = x;
left = x;
}
}
CHECK(r > 0);
CHECK(right > 0);
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
if (vt[i] >= 0 && my_vt[i] > vt[i]) {
auto S = get_source(i);
auto t = (my_vt[i] - vt[i] > r) ? r : (my_vt[i] - vt[i]);
CHECK(t > 0);
CatChainReceiverSource *S = get_source(i);
td::int32 t = (my_vt[i] - vt[i] > right) ? right : (my_vt[i] - vt[i]);
while (t-- > 0) {
auto M = S->get_block(++vt[i]);
CatChainReceivedBlock *M = S->get_block(++vt[i]);
CHECK(M != nullptr);
auto block = create_tl_object<ton_api::catchain_blockUpdate>(M->export_tl());
CHECK(M->get_payload().size() > 0);
auto BB = serialize_tl_object(block, true, M->get_payload().as_slice());
CHECK(!M->get_payload().empty());
td::BufferSlice BB = serialize_tl_object(block, true, M->get_payload().as_slice());
CHECK(BB.size() <= opts_.max_serialized_block_size);
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_message, src,
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(BB));
}
@ -798,7 +853,7 @@ void CatChainReceiverImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::cat
}
void CatChainReceiverImpl::got_fork_proof(td::BufferSlice data) {
auto F = fetch_tl_object<ton_api::catchain_differenceFork>(std::move(data), true);
auto F = fetch_tl_object<ton_api::catchain_differenceFork>(data, true);
if (F.is_error()) {
VLOG(CATCHAIN_WARNING) << this << ": received bad fork proof: " << F.move_as_error();
return;
@ -825,7 +880,7 @@ void CatChainReceiverImpl::got_fork_proof(td::BufferSlice data) {
return;
}
auto S = get_source(f->left_->src_);
CatChainReceiverSource *S = get_source(f->left_->src_);
S->on_found_fork_proof(
create_serialize_tl_object<ton_api::catchain_block_data_fork>(std::move(f->left_), std::move(f->right_)));
S->blame();
@ -835,24 +890,24 @@ void CatChainReceiverImpl::synchronize_with(CatChainReceiverSource *S) {
CHECK(!S->blamed());
std::vector<td::int32> rt(get_sources_cnt());
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
auto SS = get_source(i);
CatChainReceiverSource *SS = get_source(i);
if (SS->blamed()) {
rt[i] = -1;
} else {
rt[i] = S->delivered_height();
rt[i] = static_cast<td::int32>(S->delivered_height());
}
}
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), src = S->get_hash(), print_id = print_id()](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
VLOG(CATCHAIN_INFO) << print_id << ": timedout syncronize query to " << src;
VLOG(CATCHAIN_INFO) << print_id << ": timedout synchronize query to " << src;
return;
}
auto data = R.move_as_ok();
td::BufferSlice data = R.move_as_ok();
auto X = fetch_tl_object<ton_api::catchain_Difference>(data.clone(), true);
if (X.is_error()) {
VLOG(CATCHAIN_WARNING) << print_id << ": received incorrect answer to syncronize query from " << src << ": "
VLOG(CATCHAIN_WARNING) << print_id << ": received incorrect answer to synchronize query from " << src << ": "
<< X.move_as_error();
return;
}
@ -866,49 +921,49 @@ void CatChainReceiverImpl::synchronize_with(CatChainReceiverSource *S) {
});
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_query, S->get_adnl_id(),
get_source(local_idx_)->get_adnl_id(), overlay_id_, "sync", std::move(P),
td::Timestamp::in(5.0),
td::Timestamp::in(GET_DIFFERENCE_TIMEOUT),
serialize_tl_object(create_tl_object<ton_api::catchain_getDifference>(std::move(rt)), true));
if (S->delivered_height() < S->received_height()) {
auto B = S->get_block(S->delivered_height() + 1);
CatChainReceivedBlock *B = S->get_block(S->delivered_height() + 1);
CHECK(B->initialized());
std::vector<CatChainBlockHash> vec;
B->find_pending_deps(vec, 16);
B->find_pending_deps(vec, MAX_PENDING_DEPS);
for (auto &hash : vec) {
auto P = td::PromiseCreator::lambda(
for (const CatChainBlockHash &hash : vec) {
auto PP = td::PromiseCreator::lambda(
[SelfId = actor_id(this), print_id = print_id(), src = S->get_adnl_id()](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
VLOG(CATCHAIN_INFO) << print_id << ": timedout syncronize query to " << src;
VLOG(CATCHAIN_INFO) << print_id << ": timedout synchronize query to " << src;
} else {
td::actor::send_closure(SelfId, &CatChainReceiverImpl::receive_block_answer, src, R.move_as_ok());
}
});
auto query = serialize_tl_object(create_tl_object<ton_api::catchain_getBlock>(hash), true);
td::BufferSlice query = serialize_tl_object(create_tl_object<ton_api::catchain_getBlock>(hash), true);
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_query, S->get_adnl_id(),
get_source(local_idx_)->get_adnl_id(), overlay_id_, "sync blocks", std::move(P),
td::Timestamp::in(2.0), std::move(query));
get_source(local_idx_)->get_adnl_id(), overlay_id_, "sync blocks", std::move(PP),
td::Timestamp::in(GET_BLOCK_TIMEOUT), std::move(query));
}
}
}
void CatChainReceiverImpl::choose_neighbours() {
std::vector<td::uint32> n;
n.resize(get_max_neighbours());
n.resize(MAX_NEIGHBOURS);
td::uint32 size = 0;
for (td::uint32 i = 0; i < get_sources_cnt(); i++) {
if (i == local_idx_) {
continue;
}
auto S = get_source(i);
CatChainReceiverSource *S = get_source(i);
if (!S->blamed()) {
size++;
if (size <= n.size()) {
n[size - 1] = i;
} else {
td::uint32 id = td::Random::fast(0, size - 1);
td::uint32 id = td::Random::fast(0, static_cast<td::int32>(size) - 1);
if (id < n.size()) {
n[id] = i;
}
@ -922,15 +977,15 @@ void CatChainReceiverImpl::choose_neighbours() {
}
bool CatChainReceiverImpl::unsafe_start_up_check_completed() {
auto S = get_source(local_idx_);
CatChainReceiverSource *S = get_source(local_idx_);
CHECK(!S->blamed());
if (S->has_unreceived() || S->has_undelivered()) {
LOG(INFO) << "catchain: has_unreceived=" << S->has_unreceived() << " has_undelivered=" << S->has_undelivered();
run_scheduler();
initial_sync_complete_at_ = td::Timestamp::in(60.0);
initial_sync_complete_at_ = td::Timestamp::in(EXPECTED_INITIAL_SYNC_DURATION_WITH_UNPROCESSED);
return false;
}
auto h = S->delivered_height();
CatChainBlockHeight h = S->delivered_height();
if (h == 0) {
CHECK(last_sent_block_->get_height() == 0);
CHECK(!unsafe_root_block_writing_);
@ -941,20 +996,20 @@ bool CatChainReceiverImpl::unsafe_start_up_check_completed() {
return true;
}
if (unsafe_root_block_writing_) {
initial_sync_complete_at_ = td::Timestamp::in(5.0);
initial_sync_complete_at_ = td::Timestamp::in(EXPECTED_INITIAL_SYNC_DURATION);
LOG(INFO) << "catchain: writing=true";
return false;
}
unsafe_root_block_writing_ = true;
auto B = S->get_block(h);
CatChainReceivedBlock *B = S->get_block(h);
CHECK(B != nullptr);
CHECK(B->delivered());
CHECK(B->in_db());
auto id = B->get_hash();
CatChainBlockHash id = B->get_hash();
td::BufferSlice raw_data{32};
td::BufferSlice raw_data{id.as_array().size()};
raw_data.as_slice().copy_from(as_slice(id));
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), block = B](td::Result<td::Unit> R) mutable {
@ -963,7 +1018,7 @@ bool CatChainReceiverImpl::unsafe_start_up_check_completed() {
});
db_.set(CatChainBlockHash::zero(), std::move(raw_data), std::move(P), 0);
initial_sync_complete_at_ = td::Timestamp::in(5.0);
initial_sync_complete_at_ = td::Timestamp::in(EXPECTED_INITIAL_SYNC_DURATION);
LOG(INFO) << "catchain: need update root";
return false;
}
@ -977,9 +1032,9 @@ void CatChainReceiverImpl::written_unsafe_root_block(CatChainReceivedBlock *bloc
void CatChainReceiverImpl::alarm() {
alarm_timestamp() = td::Timestamp::never();
if (next_sync_ && next_sync_.is_in_past()) {
next_sync_ = td::Timestamp::in(td::Random::fast(0.1, 0.2));
for (auto i = 0; i < 3; i++) {
auto S = get_source(td::Random::fast(0, get_sources_cnt() - 1));
next_sync_ = td::Timestamp::in(td::Random::fast(SYNC_INTERVAL_MIN, SYNC_INTERVAL_MAX));
for (unsigned i = 0; i < SYNC_ITERATIONS; i++) {
CatChainReceiverSource *S = get_source(td::Random::fast(0, static_cast<td::int32>(get_sources_cnt()) - 1));
CHECK(S != nullptr);
if (!S->blamed()) {
synchronize_with(S);
@ -988,7 +1043,7 @@ void CatChainReceiverImpl::alarm() {
}
}
if (next_rotate_ && next_rotate_.is_in_past()) {
next_rotate_ = td::Timestamp::in(td::Random::fast(60.0, 120.0));
next_rotate_ = td::Timestamp::in(td::Random::fast(NEIGHBOURS_ROTATE_INTERVAL_MIN, NEIGHBOURS_ROTATE_INTERVAL_MAX));
choose_neighbours();
}
if (!started_ && read_db_ && initial_sync_complete_at_ && initial_sync_complete_at_.is_in_past()) {
@ -1013,58 +1068,68 @@ void CatChainReceiverImpl::send_fec_broadcast(td::BufferSlice data) {
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_broadcast_fec_ex,
get_source(local_idx_)->get_adnl_id(), overlay_id_, local_id_, 0, std::move(data));
}
void CatChainReceiverImpl::send_custom_query_data(PublicKeyHash dst, std::string name,
void CatChainReceiverImpl::send_custom_query_data(const PublicKeyHash &dst, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice query) {
auto S = get_source_by_hash(dst);
CatChainReceiverSource *S = get_source_by_hash(dst);
CHECK(S != nullptr);
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_query, S->get_adnl_id(),
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(name), std::move(promise),
timeout, std::move(query));
}
void CatChainReceiverImpl::send_custom_query_data_via(PublicKeyHash dst, std::string name,
void CatChainReceiverImpl::send_custom_query_data_via(const PublicKeyHash &dst, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice query, td::uint64 max_answer_size,
td::actor::ActorId<adnl::AdnlSenderInterface> via) {
auto S = get_source_by_hash(dst);
CatChainReceiverSource *S = get_source_by_hash(dst);
CHECK(S != nullptr);
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_query_via, S->get_adnl_id(),
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(name), std::move(promise),
timeout, std::move(query), max_answer_size, via);
}
void CatChainReceiverImpl::send_custom_message_data(PublicKeyHash dst, td::BufferSlice data) {
auto S = get_source_by_hash(dst);
void CatChainReceiverImpl::send_custom_message_data(const PublicKeyHash &dst, td::BufferSlice data) {
CatChainReceiverSource *S = get_source_by_hash(dst);
CHECK(S != nullptr);
td::actor::send_closure(overlay_manager_, &overlay::Overlays::send_message, S->get_adnl_id(),
get_source(local_idx_)->get_adnl_id(), overlay_id_, std::move(data));
}
void CatChainReceiverImpl::block_written_to_db(CatChainBlockHash hash) {
auto block = get_block(hash);
CatChainReceivedBlock *block = get_block(hash);
CHECK(block);
block->written();
run_scheduler();
}
static void destroy_db(std::string name, td::uint32 attempt) {
static void destroy_db(const std::string& name, td::uint32 attempt) {
auto S = td::RocksDb::destroy(name);
if (S.is_ok()) {
return;
}
if (S.is_error() && attempt >= 10) {
LOG(ERROR) << "failed to destroy catchain " << name << ": " << S;
} else {
if (S.is_error()) {
LOG(DEBUG) << "failed to destroy catchain " << name << ": " << S;
delay_action([name, attempt]() { destroy_db(name, attempt); }, td::Timestamp::in(1.0));
if (attempt < DESTROY_DB_MAX_ATTEMPTS) {
delay_action([name, attempt]() { destroy_db(name, attempt + 1); }, td::Timestamp::in(DESTROY_DB_DELAY));
}
}
}
void CatChainReceiverImpl::destroy() {
auto name = db_root_ + "/catchainreceiver" + db_suffix_ + td::base64url_encode(as_slice(incarnation_));
delay_action([name]() { destroy_db(name, 0); }, td::Timestamp::in(1.0));
delay_action([name]() { destroy_db(name, 0); }, td::Timestamp::in(DESTROY_DB_DELAY));
stop();
}
td::uint64 get_max_block_height(const CatChainOptions& opts, size_t sources_cnt) {
if (opts.max_block_height_coeff == 0) {
return std::numeric_limits<td::uint64>::max();
}
return opts.max_block_height_coeff * (1 + (sources_cnt + opts.max_deps - 1) / opts.max_deps) / 1000;
}
} // namespace catchain
} // namespace ton

View file

@ -44,9 +44,6 @@ class CatChainReceiver : public CatChainReceiverInterface {
CatChainSessionId instance_;
PublicKeyHash local_id_;
};
td::uint32 get_max_neighbours() const {
return 5;
}
virtual PrintId print_id() const = 0;
virtual CatChainReceivedBlock *create_block(tl_object_ptr<ton_api::catchain_block> block,
td::SharedSlice payload) = 0;
@ -64,12 +61,15 @@ class CatChainReceiver : public CatChainReceiverInterface {
virtual const CatChainOptions &opts() const = 0;
virtual td::Status validate_block_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) = 0;
virtual td::Status validate_block_sync(tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) = 0;
virtual td::Status validate_block_sync(const tl_object_ptr<ton_api::catchain_block_dep> &dep) const = 0;
virtual td::Status validate_block_sync(const tl_object_ptr<ton_api::catchain_block> &block,
const td::Slice &payload) const = 0;
virtual ~CatChainReceiver() = default;
};
td::uint64 get_max_block_height(const CatChainOptions& opts, size_t sources_cnt);
} // namespace catchain
} // namespace ton

View file

@ -33,7 +33,7 @@ namespace ton {
namespace catchain {
class CatChainReceiverImpl : public CatChainReceiver {
class CatChainReceiverImpl final : public CatChainReceiver {
public:
PrintId print_id() const override {
return PrintId{incarnation_, local_id_};
@ -62,7 +62,7 @@ class CatChainReceiverImpl : public CatChainReceiver {
return sources_[source_id].get();
}
PublicKeyHash get_source_hash(td::uint32 source_id) const override;
CatChainReceiverSource *get_source_by_hash(PublicKeyHash source_hash) const;
CatChainReceiverSource *get_source_by_hash(const PublicKeyHash &source_hash) const;
CatChainReceiverSource *get_source_by_adnl_id(adnl::AdnlNodeIdShort source_hash) const;
td::uint32 add_fork() override;
@ -72,39 +72,39 @@ class CatChainReceiverImpl : public CatChainReceiver {
void receive_message_from_overlay(adnl::AdnlNodeIdShort src, td::BufferSlice data);
void receive_query_from_overlay(adnl::AdnlNodeIdShort src, td::BufferSlice data,
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlock &query,
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlock query, td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlocks query,
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlocks &query,
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlockHistory query,
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlockHistory &query,
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getDifference &query,
void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getDifference query,
td::Promise<td::BufferSlice> promise);
template <class T>
void process_query(adnl::AdnlNodeIdShort src, T &query, td::Promise<td::BufferSlice> promise) {
void process_query(adnl::AdnlNodeIdShort src, const T &query, td::Promise<td::BufferSlice> promise) {
//LOG(WARNING) << this << ": unknown query from " << src;
callback_->on_custom_query(get_source_by_adnl_id(src)->get_hash(), serialize_tl_object(&query, true),
std::move(promise));
}
void receive_broadcast_from_overlay(PublicKeyHash src, td::BufferSlice data);
void receive_broadcast_from_overlay(const PublicKeyHash &src, td::BufferSlice data);
void receive_block(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
void receive_block_answer(adnl::AdnlNodeIdShort src, td::BufferSlice);
//void send_block(PublicKeyHash src, tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
//void send_block(const PublicKeyHash &src, tl_object_ptr<ton_api::catchain_block> block, td::BufferSlice payload);
CatChainReceivedBlock *create_block(tl_object_ptr<ton_api::catchain_block> block, td::SharedSlice payload) override;
CatChainReceivedBlock *create_block(tl_object_ptr<ton_api::catchain_block_dep> block) override;
td::Status validate_block_sync(tl_object_ptr<ton_api::catchain_block_dep> &dep) override;
td::Status validate_block_sync(tl_object_ptr<ton_api::catchain_block> &block, td::Slice payload) override;
td::Status validate_block_sync(const tl_object_ptr<ton_api::catchain_block_dep> &dep) const override;
td::Status validate_block_sync(const tl_object_ptr<ton_api::catchain_block> &block,
const td::Slice &payload) const override;
void send_fec_broadcast(td::BufferSlice data) override;
void send_custom_query_data(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
void send_custom_query_data(const PublicKeyHash &dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice query) override;
void send_custom_query_data_via(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
void send_custom_query_data_via(const PublicKeyHash &dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice query, td::uint64 max_answer_size,
td::actor::ActorId<adnl::AdnlSenderInterface> via) override;
void send_custom_message_data(PublicKeyHash dst, td::BufferSlice query) override;
void send_custom_message_data(const PublicKeyHash &dst, td::BufferSlice query) override;
void run_scheduler();
void add_block(td::BufferSlice data, std::vector<CatChainBlockHash> deps) override;
@ -117,8 +117,6 @@ class CatChainReceiverImpl : public CatChainReceiver {
void on_blame(td::uint32 src) override {
callback_->blame(src);
}
void blame_node(td::uint32 idx) override {
}
const CatChainOptions &opts() const override {
return opts_;
}
@ -141,11 +139,11 @@ class CatChainReceiverImpl : public CatChainReceiver {
CatChainReceivedBlock *get_block(CatChainBlockHash hash) const;
CatChainReceiverImpl(std::unique_ptr<Callback> callback, CatChainOptions opts,
CatChainReceiverImpl(std::unique_ptr<Callback> callback, const CatChainOptions &opts,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<overlay::Overlays>, std::vector<CatChainNode> ids, PublicKeyHash local_id,
CatChainBlockHash unique_hash, std::string db_root, std::string db_suffix,
bool allow_unsafe_self_blocks_resync);
td::actor::ActorId<overlay::Overlays> overlays, const std::vector<CatChainNode> &ids,
const PublicKeyHash &local_id, const CatChainBlockHash &unique_hash, std::string db_root,
std::string db_suffix, bool allow_unsafe_self_blocks_resync);
private:
std::unique_ptr<overlay::Overlays::Callback> make_callback() {
@ -164,7 +162,7 @@ class CatChainReceiverImpl : public CatChainReceiver {
void receive_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
td::actor::send_closure(id_, &CatChainReceiverImpl::receive_broadcast_from_overlay, src, std::move(data));
}
Callback(td::actor::ActorId<CatChainReceiverImpl> id) : id_(std::move(id)) {
explicit Callback(td::actor::ActorId<CatChainReceiverImpl> id) : id_(std::move(id)) {
}
private:
@ -199,7 +197,7 @@ class CatChainReceiverImpl : public CatChainReceiver {
CatChainReceivedBlock *root_block_;
CatChainReceivedBlock *last_sent_block_;
CatChainSessionId incarnation_;
CatChainSessionId incarnation_{};
std::unique_ptr<Callback> callback_;
CatChainOptions opts_;

View file

@ -20,6 +20,7 @@
#include "td/utils/int_types.h"
#include "adnl/adnl-node-id.hpp"
#include "ton/ton-types.h"
namespace ton {
@ -35,13 +36,6 @@ struct CatChainNode {
PublicKey pub_key;
};
struct CatChainOptions {
double idle_timeout = 16.0;
td::uint32 max_deps = 4;
bool debug_disable_db = false;
};
} // namespace catchain
} // namespace ton

View file

@ -18,9 +18,9 @@
*/
#include "catchain-types.h"
#include "catchain.hpp"
#include "catchain-receiver.h"
#include "adnl/utils.hpp"
#include <utility>
#include "catchain-receiver.h"
namespace ton {
@ -32,10 +32,11 @@ void CatChainImpl::send_process() {
std::vector<CatChainBlock *> v;
std::vector<CatChainBlockHash> w;
while (top_blocks_.size() > 0 && v.size() < opts_.max_deps) {
auto B = *top_blocks_.get_random();
CatChainBlock *B = *top_blocks_.get_random();
CHECK(B != nullptr);
top_blocks_.remove(B->hash());
if (B->source() == sources_.size() || !blamed_sources_[B->source()]) {
CHECK(B->source() < sources_.size());
if (!blamed_sources_[B->source()]) {
w.push_back(B->hash());
v.push_back(B);
set_processed(B);
@ -52,13 +53,13 @@ void CatChainImpl::send_preprocess(CatChainBlock *block) {
if (block->preprocess_is_sent()) {
return;
}
auto prev = block->prev();
CatChainBlock *prev = block->prev();
if (prev) {
send_preprocess(prev);
}
auto deps = block->deps();
for (auto X : deps) {
const std::vector<CatChainBlock *> &deps = block->deps();
for (CatChainBlock *X : deps) {
send_preprocess(X);
}
@ -72,13 +73,13 @@ void CatChainImpl::set_processed(CatChainBlock *block) {
if (block->is_processed()) {
return;
}
auto prev = block->prev();
CatChainBlock *prev = block->prev();
if (prev) {
set_processed(prev);
}
auto deps = block->deps();
for (auto X : deps) {
const std::vector<CatChainBlock *> &deps = block->deps();
for (CatChainBlock *X : deps) {
set_processed(X);
}
@ -133,6 +134,7 @@ void CatChainImpl::on_new_block(td::uint32 src_id, td::uint32 fork, CatChainBloc
}
}
CHECK(src_id < sources_.size());
std::vector<CatChainBlock *> v;
v.resize(deps.size());
for (size_t i = 0; i < deps.size(); i++) {
@ -143,12 +145,12 @@ void CatChainImpl::on_new_block(td::uint32 src_id, td::uint32 fork, CatChainBloc
CHECK(v[i] != nullptr);
}
CHECK(src_id < sources_.size());
auto src_hash = sources_[src_id];
CHECK(height <= get_max_block_height(opts_, sources_.size()));
PublicKeyHash src_hash = sources_[src_id];
blocks_[hash] =
CatChainBlock::create(src_id, fork, src_hash, height, hash, std::move(data), p, std::move(v), std::move(vt));
auto B = get_block(hash);
CatChainBlock *B = get_block(hash);
CHECK(B != nullptr);
if (!blamed_sources_[src_id]) {
@ -177,7 +179,7 @@ void CatChainImpl::on_blame(td::uint32 src_id) {
auto size = static_cast<td::uint32>(sources_.size());
for (td::uint32 i = 0; i < size; i++) {
if (!blamed_sources_[i] && top_source_blocks_[i] && i != local_idx_) {
auto B = top_source_blocks_[i];
CatChainBlock *B = top_source_blocks_[i];
bool f = true;
if (B->is_processed()) {
continue;
@ -197,15 +199,11 @@ void CatChainImpl::on_blame(td::uint32 src_id) {
}
}
void CatChainImpl::on_custom_message(PublicKeyHash src, td::BufferSlice data) {
callback_->process_message(src, std::move(data));
}
void CatChainImpl::on_custom_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
void CatChainImpl::on_custom_query(const PublicKeyHash &src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
callback_->process_query(src, std::move(data), std::move(promise));
}
void CatChainImpl::on_broadcast(PublicKeyHash src, td::BufferSlice data) {
void CatChainImpl::on_broadcast(const PublicKeyHash &src, td::BufferSlice data) {
VLOG(CATCHAIN_INFO) << this << ": processing broadcast";
callback_->process_broadcast(src, std::move(data));
VLOG(CATCHAIN_INFO) << this << ": sent processing broadcast";
@ -219,18 +217,18 @@ void CatChainImpl::on_receiver_started() {
send_process();
}
CatChainImpl::CatChainImpl(std::unique_ptr<Callback> callback, CatChainOptions opts,
CatChainImpl::CatChainImpl(std::unique_ptr<Callback> callback, const CatChainOptions &opts,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<overlay::Overlays> overlay_manager, std::vector<CatChainNode> ids,
PublicKeyHash local_id, CatChainSessionId unique_hash, std::string db_root,
std::string db_suffix, bool allow_unsafe_self_blocks_resync)
: opts_(std::move(opts))
, db_root_(db_root)
, db_suffix_(db_suffix)
const PublicKeyHash &local_id, const CatChainSessionId &unique_hash,
std::string db_root, std::string db_suffix, bool allow_unsafe_self_blocks_resync)
: opts_(opts)
, unique_hash_(unique_hash)
, db_root_(std::move(db_root))
, db_suffix_(std::move(db_suffix))
, allow_unsafe_self_blocks_resync_(allow_unsafe_self_blocks_resync) {
callback_ = std::move(callback);
sources_.resize(ids.size());
unique_hash_ = unique_hash;
for (size_t i = 0; i < ids.size(); i++) {
sources_[i] = ids[i].pub_key.compute_short_id();
if (sources_[i] == local_id) {
@ -240,7 +238,8 @@ CatChainImpl::CatChainImpl(std::unique_ptr<Callback> callback, CatChainOptions o
blamed_sources_.resize(ids.size(), false);
top_source_blocks_.resize(ids.size(), nullptr);
args_ = std::make_unique<Args>(keyring, adnl, overlay_manager, std::move(ids), local_id, unique_hash);
args_ = std::make_unique<Args>(std::move(keyring), std::move(adnl), std::move(overlay_manager), std::move(ids),
local_id, unique_hash);
}
void CatChainImpl::alarm() {
@ -263,19 +262,16 @@ void CatChainImpl::start_up() {
void blame(td::uint32 src_id) override {
td::actor::send_closure(id_, &CatChainImpl::on_blame, src_id);
}
void on_custom_message(PublicKeyHash src, td::BufferSlice data) override {
td::actor::send_closure(id_, &CatChainImpl::on_custom_message, src, std::move(data));
}
void on_custom_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
void on_custom_query(const PublicKeyHash &src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &CatChainImpl::on_custom_query, src, std::move(data), std::move(promise));
}
void on_broadcast(PublicKeyHash src, td::BufferSlice data) override {
void on_broadcast(const PublicKeyHash &src, td::BufferSlice data) override {
td::actor::send_closure(id_, &CatChainImpl::on_broadcast, src, std::move(data));
}
void start() override {
td::actor::send_closure(id_, &CatChainImpl::on_receiver_started);
}
ChainCb(td::actor::ActorId<CatChainImpl> id) : id_(id) {
explicit ChainCb(td::actor::ActorId<CatChainImpl> id) : id_(std::move(id)) {
}
private:
@ -285,22 +281,23 @@ void CatChainImpl::start_up() {
auto cb = std::make_unique<ChainCb>(actor_id(this));
receiver_ = CatChainReceiverInterface::create(
std::move(cb), opts_, args_->keyring, args_->adnl, args_->overlay_manager, std::move(args_->ids), args_->local_id,
std::move(cb), opts_, args_->keyring, args_->adnl, args_->overlay_manager, args_->ids, args_->local_id,
args_->unique_hash, db_root_, db_suffix_, allow_unsafe_self_blocks_resync_);
args_ = nullptr;
//alarm_timestamp() = td::Timestamp::in(opts_.idle_timeout);
}
td::actor::ActorOwn<CatChain> CatChain::create(std::unique_ptr<Callback> callback, CatChainOptions opts,
td::actor::ActorOwn<CatChain> CatChain::create(std::unique_ptr<Callback> callback, const CatChainOptions &opts,
td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<overlay::Overlays> overlay_manager,
std::vector<CatChainNode> ids, PublicKeyHash local_id,
CatChainSessionId unique_hash, std::string db_root,
std::vector<CatChainNode> ids, const PublicKeyHash &local_id,
const CatChainSessionId &unique_hash, std::string db_root,
std::string db_suffix, bool allow_unsafe_self_blocks_resync) {
return td::actor::create_actor<CatChainImpl>("catchain", std::move(callback), std::move(opts), keyring, adnl,
overlay_manager, std::move(ids), local_id, unique_hash, db_root,
db_suffix, allow_unsafe_self_blocks_resync);
return td::actor::create_actor<CatChainImpl>("catchain", std::move(callback), opts, std::move(keyring),
std::move(adnl), std::move(overlay_manager), std::move(ids),
local_id, unique_hash, std::move(db_root), std::move(db_suffix),
allow_unsafe_self_blocks_resync);
}
CatChainBlock *CatChainImpl::get_block(CatChainBlockHash hash) const {

View file

@ -58,8 +58,8 @@ class CatChainBlock {
virtual bool is_descendant_of(CatChainBlock *block) = 0;
static std::unique_ptr<CatChainBlock> create(td::uint32 src, td::uint32 fork_id, PublicKeyHash src_hash,
CatChainBlockHeight height, CatChainBlockHash hash,
static std::unique_ptr<CatChainBlock> create(td::uint32 src, td::uint32 fork_id, const PublicKeyHash &src_hash,
CatChainBlockHeight height, const CatChainBlockHash &hash,
td::SharedSlice payload, CatChainBlock *prev,
std::vector<CatChainBlock *> deps, std::vector<CatChainBlockHeight> vt);
@ -73,9 +73,10 @@ class CatChain : public td::actor::Actor {
virtual void process_blocks(std::vector<CatChainBlock *> blocks) = 0;
virtual void finished_processing() = 0;
virtual void preprocess_block(CatChainBlock *block) = 0;
virtual void process_broadcast(PublicKeyHash src, td::BufferSlice data) = 0;
virtual void process_message(PublicKeyHash src, td::BufferSlice data) = 0;
virtual void process_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
virtual void process_broadcast(const PublicKeyHash &src, td::BufferSlice data) = 0;
virtual void process_message(const PublicKeyHash &src, td::BufferSlice data) = 0;
virtual void process_query(const PublicKeyHash &src, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) = 0;
virtual void started() = 0;
virtual ~Callback() = default;
};
@ -89,22 +90,22 @@ class CatChain : public td::actor::Actor {
virtual void debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height) = 0;
virtual void send_broadcast(td::BufferSlice data) = 0;
virtual void send_message(PublicKeyHash dst, td::BufferSlice data) = 0;
virtual void send_query(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
virtual void send_message(const PublicKeyHash &dst, td::BufferSlice data) = 0;
virtual void send_query(const PublicKeyHash &dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice query) = 0;
virtual void send_query_via(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise,
virtual void send_query_via(const PublicKeyHash &dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice query, td::uint64 max_answer_size,
td::actor::ActorId<adnl::AdnlSenderInterface> via) = 0;
virtual void destroy() = 0;
static td::actor::ActorOwn<CatChain> create(std::unique_ptr<Callback> callback, CatChainOptions opts,
static td::actor::ActorOwn<CatChain> create(std::unique_ptr<Callback> callback, const CatChainOptions &opts,
td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<overlay::Overlays> overlay_manager,
std::vector<CatChainNode> ids, PublicKeyHash local_id,
CatChainSessionId unique_hash, std::string db_root, std::string db_suffix,
bool allow_unsafe_self_blocks_resync);
virtual ~CatChain() = default;
std::vector<CatChainNode> ids, const PublicKeyHash &local_id,
const CatChainSessionId &unique_hash, std::string db_root,
std::string db_suffix, bool allow_unsafe_self_blocks_resync);
~CatChain() override = default;
};
} // namespace catchain

View file

@ -67,11 +67,11 @@ class CatChainImpl : public CatChain {
CatChainSessionId unique_hash;
Args(td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<overlay::Overlays> overlay_manager, std::vector<CatChainNode> ids, PublicKeyHash local_id,
CatChainSessionId unique_hash)
: keyring(keyring)
, adnl(adnl)
, overlay_manager(overlay_manager)
td::actor::ActorId<overlay::Overlays> overlay_manager, std::vector<CatChainNode> ids,
const PublicKeyHash &local_id, const CatChainSessionId &unique_hash)
: keyring(std::move(keyring))
, adnl(std::move(adnl))
, overlay_manager(std::move(overlay_manager))
, ids(std::move(ids))
, local_id(local_id)
, unique_hash(unique_hash) {
@ -88,9 +88,8 @@ class CatChainImpl : public CatChain {
CatChainBlockHash prev, std::vector<CatChainBlockHash> deps, std::vector<CatChainBlockHeight> vt,
td::SharedSlice data);
void on_blame(td::uint32 src_id);
void on_custom_message(PublicKeyHash src, td::BufferSlice data);
void on_custom_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void on_broadcast(PublicKeyHash src, td::BufferSlice data);
void on_custom_query(const PublicKeyHash &src, td::BufferSlice data, td::Promise<td::BufferSlice> promise);
void on_broadcast(const PublicKeyHash &src, td::BufferSlice data);
void on_receiver_started();
void processed_block(td::BufferSlice payload) override;
void need_new_block(td::Timestamp t) override;
@ -102,25 +101,26 @@ class CatChainImpl : public CatChain {
void send_broadcast(td::BufferSlice data) override {
td::actor::send_closure(receiver_, &CatChainReceiverInterface::send_fec_broadcast, std::move(data));
}
void send_message(PublicKeyHash dst, td::BufferSlice data) override {
void send_message(const PublicKeyHash &dst, td::BufferSlice data) override {
td::actor::send_closure(receiver_, &CatChainReceiverInterface::send_custom_message_data, dst, std::move(data));
}
void send_query(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice query) override {
void send_query(const PublicKeyHash &dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice query) override {
td::actor::send_closure(receiver_, &CatChainReceiverInterface::send_custom_query_data, dst, name,
std::move(promise), timeout, std::move(query));
}
void send_query_via(PublicKeyHash dst, std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice query, td::uint64 max_answer_size,
void send_query_via(const PublicKeyHash &dst, std::string name, td::Promise<td::BufferSlice> promise,
td::Timestamp timeout, td::BufferSlice query, td::uint64 max_answer_size,
td::actor::ActorId<adnl::AdnlSenderInterface> via) override {
td::actor::send_closure(receiver_, &CatChainReceiverInterface::send_custom_query_data_via, dst, name,
std::move(promise), timeout, std::move(query), max_answer_size, via);
}
void destroy() override;
CatChainImpl(std::unique_ptr<Callback> callback, CatChainOptions opts, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<overlay::Overlays> overlay_manager,
std::vector<CatChainNode> ids, PublicKeyHash local_id, CatChainSessionId unique_hash,
std::string db_root, std::string db_suffix, bool allow_unsafe_self_blocks_resync);
CatChainImpl(std::unique_ptr<Callback> callback, const CatChainOptions &opts,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<overlay::Overlays> overlay_manager, std::vector<CatChainNode> ids,
const PublicKeyHash &local_id, const CatChainSessionId &unique_hash, std::string db_root,
std::string db_suffix, bool allow_unsafe_self_blocks_resync);
void alarm() override;
void start_up() override;

View file

@ -703,6 +703,13 @@ consensus_config_v3#d8 flags:(## 7) { flags = 0 } new_catchain_ids:Bool
max_block_bytes:uint32 max_collated_bytes:uint32
proto_version:uint16 = ConsensusConfig;
consensus_config_v4#d9 flags:(## 7) { flags = 0 } new_catchain_ids:Bool
round_candidates:(## 8) { round_candidates >= 1 }
next_candidate_delay_ms:uint32 consensus_timeout_ms:uint32
fast_attempts:uint32 attempt_duration:uint32 catchain_max_deps:uint32
max_block_bytes:uint32 max_collated_bytes:uint32
proto_version:uint16 catchain_max_blocks_coeff:uint32 = ConsensusConfig;
_ CatchainConfig = ConfigParam 28;
_ ConsensusConfig = ConfigParam 29;

View file

@ -310,32 +310,52 @@ td::Status Config::visit_validator_params() const {
ton::ValidatorSessionConfig Config::get_consensus_config() const {
auto cc = get_config_param(29);
ton::ValidatorSessionConfig c;
auto set = [&c](auto& r) {
c.catchain_idle_timeout = r.consensus_timeout_ms * 0.001;
c.catchain_max_deps = r.catchain_max_deps;
auto set_v1 = [&](auto& r) {
c.catchain_opts.idle_timeout = r.consensus_timeout_ms * 0.001;
c.catchain_opts.max_deps = r.catchain_max_deps;
c.round_candidates = r.round_candidates;
c.next_candidate_delay = r.next_candidate_delay_ms * 0.001;
c.round_attempt_duration = r.attempt_duration;
c.max_round_attempts = r.fast_attempts;
c.max_block_size = r.max_block_bytes;
c.max_collated_data_size = r.max_collated_bytes;
return true;
};
auto set_new_cc_ids = [&c] (auto& r) {
auto set_v2 = [&] (auto& r) {
set_v1(r);
c.new_catchain_ids = r.new_catchain_ids;
return true;
};
auto set_proto = [&c](auto& r) {
auto set_v3 = [&](auto& r) {
set_v2(r);
c.proto_version = r.proto_version;
return true;
};
auto set_v4 = [&](auto& r) {
set_v3(r);
td::uint64 max_blocks_coeff = r.catchain_max_blocks_coeff;
if (max_blocks_coeff == 0) {
c.catchain_opts.max_block_height_coeff = 0;
} else {
auto catchain_config = get_catchain_validators_config();
td::uint64 catchain_lifetime = std::max(catchain_config.mc_cc_lifetime, catchain_config.shard_cc_lifetime);
c.catchain_opts.max_block_height_coeff = catchain_lifetime * max_blocks_coeff;
}
};
if (cc.not_null()) {
block::gen::ConsensusConfig::Record_consensus_config_v3 r2;
block::gen::ConsensusConfig::Record_consensus_config_new r1;
block::gen::ConsensusConfig::Record_consensus_config r0;
(tlb::unpack_cell(cc, r2) && set(r2) && set_new_cc_ids(r2) && set_proto(r2)) ||
(tlb::unpack_cell(cc, r1) && set(r1) && set_new_cc_ids(r1)) ||
(tlb::unpack_cell(cc, r0) && set(r0));
block::gen::ConsensusConfig::Record_consensus_config_v4 r4;
block::gen::ConsensusConfig::Record_consensus_config_v3 r3;
block::gen::ConsensusConfig::Record_consensus_config_new r2;
block::gen::ConsensusConfig::Record_consensus_config r1;
if (tlb::unpack_cell(cc, r4)) {
set_v4(r4);
} else if (tlb::unpack_cell(cc, r3)) {
set_v3(r3);
} else if (tlb::unpack_cell(cc, r2)) {
set_v2(r2);
} else if (tlb::unpack_cell(cc, r1)) {
set_v1(r1);
}
}
if (c.proto_version >= ton::ValidatorSessionConfig::BLOCK_HASH_COVERS_DATA_FROM_VERSION) {
c.catchain_opts.block_hash_covers_data = true;
}
return c;
}

22
doc/catchain-dos.md Normal file
View file

@ -0,0 +1,22 @@
# Catchain DoS protection
## Consensus-safe upgrade
Since catchain protocol describes the way validators come to consensus, it should be updated in simultaneous manner to ensure that at any moment of time at least 2/3 of validators (measured by weight) are using the same version of the protocol. Innate way to do it in TON is to use Configuration parameters, when absence or old version of some configuration parameter corresponds to the old behavior, while new version controls updated catchain protocol behavior.
That way, update of catchain protocol should be done in the following way: each validator upgrades its node software and votes for a new config parameter. This method ensures that switching to updated catchain protocol will happen only after 3/4 (more than 2/3) of validators upgrade.
## Covering block dependencies by hash
Catchain protocol version is controlled by `ConfigParam 29`: `proto_version` field in constructors `consensus_config_v3` and older (for other constructors `proto_version` is equal to `0`).
For catchain protocol version higher or equal to 2 hash covers catchain block dependencies, that prevents relaying of blocks with altered dependencies.
## Limiting maximal catchain block height and size
### Catchain block size
All catchain messages, except `REJECT` message, have (and had) a limited size. After update `REJECT` message will be limited to 1024 bytes. At the same time one block contains at most number of block candidates per round messages. That way, 16kb limit per catchain block should be enough to prevent DoS.
### Limiting block height
Another potential DoS is related to a situation when a malbehaviouring node sends too many catchain blocks. Note that limiting of maximal number of blocks per second is not a good solution since it will hinder synchronization after node disconnect.
At the same time, catchain groups exist for quite short period of time (around a few hunderd seconds), while number of blocks production is determined by "natural block production speed" on the one hand and number of blocks generated to decrease dependencies size on the other. In any case, total number of blocks is limited by `catchain_lifetime * natural_block_production_speed * (1 + number_of_catchain_participants / max_dependencies_size)`.
To prevent DoS attack we limit maximal height of the block which will be processed by node by `catchain_lifetime * natural_block_production_speed * (1 + number_of_catchain_participants / max_dependencies_size)`, where `catchain_lifetime` is set by `ConfigParam 28` (`CatchainConfig`), `natural_block_production_speed` and `max_dependencies_size` are set by `ConfigParam 29` (`ConsensusConfig`) (`natural_block_production_speed` is calculated as `catchain_max_blocks_coeff / 1000`) and `number_of_catchain_participants` is set from catchain group configuration.
By default, `catchain_max_blocks_coeff` is set to zero: special value which means that there is no limitation on catchain block height. It is recommended to set `catchain_max_blocks_coeff` to `10000`: we expect that natural production rate is about one block per 3 seconds, so we set the coefficient to allow 30 times higher block production than expected. At the same time, this number is low enough to prevent resource-intensive attacks.
To prevent DoS with many blocks of the same height, nodes will ignore any blocks from a "bad" node (i.e. one which created a fork) unless the new block is required by some other block from a "good" node.

View file

@ -122,8 +122,9 @@ class CatChainInst : public td::actor::Actor {
void start_up() override {
alarm_timestamp() = td::Timestamp::in(0.1);
ton::catchain::CatChainOptions opts;
ton::CatChainOptions opts;
opts.debug_disable_db = true;
//opts.block_hash_covers_data = true;
std::vector<ton::catchain::CatChainNode> nodes;
for (auto &n : nodes_) {
@ -157,13 +158,14 @@ class CatChainInst : public td::actor::Actor {
void preprocess_block(ton::catchain::CatChainBlock *block) override {
td::actor::send_closure(id_, &CatChainInst::preprocess_block, std::move(block));
}
void process_broadcast(ton::PublicKeyHash src, td::BufferSlice data) override {
void process_broadcast(const ton::PublicKeyHash &src, td::BufferSlice data) override {
UNREACHABLE();
}
void process_message(ton::PublicKeyHash src, td::BufferSlice data) override {
void process_message(const ton::PublicKeyHash &src, td::BufferSlice data) override {
UNREACHABLE();
}
void process_query(ton::PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
void process_query(const ton::PublicKeyHash &src, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
UNREACHABLE();
}
void started() override {

View file

@ -259,7 +259,7 @@ catchain.blockUpdate block:catchain.block = catchain.Update;
catchain.block.data.badBlock block:catchain.block = catchain.block.inner.Data;
catchain.block.data.fork left:catchain.block.Dep right:catchain.block.Dep = catchain.block.inner.Data;
catchain.block.data.nop = catchain.block.inner.Data;
catchain.block.data.vector msgs:(vector bytes) = catchain.block.inner.Data;
//catchain.block.data.vector msgs:(vector bytes) = catchain.block.inner.Data;
//catchain.block.data.custom = catchain.block.inner.Data;
catchain.firstblock unique_hash:int256 nodes:(vector int256) = catchain.FirstBlock;
@ -309,11 +309,14 @@ validatorSession.candidate src:int256 round:int root_hash:int256 data:bytes coll
validatorSession.config catchain_idle_timeout:double catchain_max_deps:int round_candidates:int next_candidate_delay:double round_attempt_duration:int
max_round_attempts:int max_block_size:int max_collated_data_size:int = validatorSession.Config;
validatorSession.configVersioned catchain_idle_timeout:double catchain_max_deps:int round_candidates:int next_candidate_delay:double round_attempt_duration:int
max_round_attempts:int max_block_size:int max_collated_data_size:int version:int = validatorSession.Config;
validatorSession.configNew catchain_idle_timeout:double catchain_max_deps:int round_candidates:int next_candidate_delay:double round_attempt_duration:int
max_round_attempts:int max_block_size:int max_collated_data_size:int new_catchain_ids:Bool = validatorSession.Config;
validatorSession.catchainOptions idle_timeout:double max_deps:int max_block_size:int block_hash_covers_data:Bool
max_block_height_ceoff:int debug_disable_db:Bool = validatorSession.CatChainOptions;
validatorSession.configVersioned catchain_opts:validatorSession.CatChainOptions round_candidates:int next_candidate_delay:double
round_attempt_duration:int max_round_attempts:int max_block_size:int max_collated_data_size:int version:int = validatorSession.Config;
---functions---
validatorSession.ping hash:long = validatorSession.Pong;

Binary file not shown.

View file

@ -24,6 +24,7 @@
#include "td/utils/Slice.h"
#include "td/utils/UInt.h"
#include "td/utils/misc.h"
#include "td/utils/optional.h"
#include <cinttypes>
@ -447,11 +448,23 @@ struct ValidatorDescr {
}
};
struct CatChainOptions {
double idle_timeout = 16.0;
td::uint32 max_deps = 4;
td::uint32 max_serialized_block_size = 16 * 1024;
bool block_hash_covers_data = false;
// Max block height = max_block_height_coeff * (1 + N / max_deps) / 1000
// N - number of participants
// 0 - unlimited
td::uint64 max_block_height_coeff = 0;
bool debug_disable_db = false;
};
struct ValidatorSessionConfig {
td::uint32 proto_version = 0;
/* double */ double catchain_idle_timeout = 16.0;
td::uint32 catchain_max_deps = 4;
CatChainOptions catchain_opts;
td::uint32 round_candidates = 3;
/* double */ double next_candidate_delay = 2.0;
@ -462,6 +475,8 @@ struct ValidatorSessionConfig {
td::uint32 max_collated_data_size = (4 << 20);
bool new_catchain_ids = false;
static const td::uint32 BLOCK_HASH_COVERS_DATA_FROM_VERSION = 2;
};
} // namespace ton

View file

@ -37,11 +37,10 @@ inline ValidatorSessionCandidateId skip_round_candidate_id() {
}
struct ValidatorSessionOptions {
ValidatorSessionOptions() {
}
ValidatorSessionOptions(const ValidatorSessionConfig &conf);
double catchain_idle_timeout = 16.0;
td::uint32 catchain_max_deps = 4;
ValidatorSessionOptions() = default;
explicit ValidatorSessionOptions(const ValidatorSessionConfig &conf);
CatChainOptions catchain_opts;
td::uint32 round_candidates = 3;
double next_candidate_delay = 2.0;

View file

@ -337,6 +337,9 @@ void ValidatorSessionImpl::candidate_decision_fail(td::uint32 round, ValidatorSe
}
LOG(ERROR) << this << ": failed candidate " << hash << ": " << result;
pending_approve_.erase(hash);
if (result.size() > MAX_REJECT_REASON_SIZE) {
result.resize(MAX_REJECT_REASON_SIZE);
}
pending_reject_.emplace(hash, td::BufferSlice{result});
rejected_.insert(hash);
}
@ -840,10 +843,8 @@ void ValidatorSessionImpl::start() {
auto w = description().export_catchain_nodes();
catchain_ = catchain::CatChain::create(
make_catchain_callback(),
catchain::CatChainOptions{description().opts().catchain_idle_timeout, description().opts().catchain_max_deps},
keyring_, adnl_, overlay_manager_, std::move(w), local_id(), unique_hash_, db_root_, db_suffix_,
allow_unsafe_self_blocks_resync_);
make_catchain_callback(), description().opts().catchain_opts, keyring_, adnl_, overlay_manager_, std::move(w),
local_id(), unique_hash_, db_root_, db_suffix_, allow_unsafe_self_blocks_resync_);
check_all();
}
@ -883,26 +884,27 @@ td::actor::ActorOwn<ValidatorSession> ValidatorSession::create(
td::Bits256 ValidatorSessionOptions::get_hash() const {
if(!proto_version) {
if (!new_catchain_ids) {
return create_hash_tl_object<ton_api::validatorSession_config>(
catchain_idle_timeout, catchain_max_deps, round_candidates, next_candidate_delay, round_attempt_duration,
max_round_attempts, max_block_size, max_collated_data_size);
return create_hash_tl_object<ton_api::validatorSession_config>(
catchain_opts.idle_timeout, catchain_opts.max_deps, round_candidates, next_candidate_delay,
round_attempt_duration, max_round_attempts, max_block_size, max_collated_data_size);
} else {
return create_hash_tl_object<ton_api::validatorSession_configNew>(
catchain_idle_timeout, catchain_max_deps, round_candidates, next_candidate_delay, round_attempt_duration,
max_round_attempts, max_block_size, max_collated_data_size, new_catchain_ids);
return create_hash_tl_object<ton_api::validatorSession_configNew>(
catchain_opts.idle_timeout, catchain_opts.max_deps, round_candidates, next_candidate_delay,
round_attempt_duration, max_round_attempts, max_block_size, max_collated_data_size, new_catchain_ids);
}
} else {
return create_hash_tl_object<ton_api::validatorSession_configVersioned>(
catchain_idle_timeout, catchain_max_deps, round_candidates, next_candidate_delay, round_attempt_duration,
max_round_attempts, max_block_size, max_collated_data_size, proto_version);
}
return create_hash_tl_object<ton_api::validatorSession_configVersioned>(
create_tl_object<ton_api::validatorSession_catchainOptions>(
catchain_opts.idle_timeout, catchain_opts.max_deps, catchain_opts.max_serialized_block_size,
catchain_opts.block_hash_covers_data, catchain_opts.max_block_height_coeff, catchain_opts.debug_disable_db),
round_candidates, next_candidate_delay, round_attempt_duration,
max_round_attempts, max_block_size, max_collated_data_size, proto_version);
}
}
ValidatorSessionOptions::ValidatorSessionOptions(const ValidatorSessionConfig &conf) {
proto_version = conf.proto_version;
catchain_idle_timeout = conf.catchain_idle_timeout;
catchain_max_deps = conf.catchain_max_deps;
catchain_opts = conf.catchain_opts;
max_block_size = conf.max_block_size;
max_collated_data_size = conf.max_collated_data_size;
max_round_attempts = conf.max_round_attempts;

View file

@ -109,13 +109,14 @@ class ValidatorSessionImpl : public ValidatorSession {
void preprocess_block(catchain::CatChainBlock *block) override {
td::actor::send_closure(id_, &ValidatorSessionImpl::preprocess_block, block);
}
void process_broadcast(PublicKeyHash src, td::BufferSlice data) override {
void process_broadcast(const PublicKeyHash &src, td::BufferSlice data) override {
td::actor::send_closure(id_, &ValidatorSessionImpl::process_broadcast, src, std::move(data));
}
void process_message(PublicKeyHash src, td::BufferSlice data) override {
void process_message(const PublicKeyHash &src, td::BufferSlice data) override {
td::actor::send_closure(id_, &ValidatorSessionImpl::process_message, src, std::move(data));
}
void process_query(PublicKeyHash src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override {
void process_query(const PublicKeyHash &src, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &ValidatorSessionImpl::process_query, src, std::move(data), std::move(promise));
}
void started() override {
@ -195,6 +196,9 @@ class ValidatorSessionImpl : public ValidatorSession {
PrintId print_id() const override {
return PrintId{unique_hash_, description_->get_source_id(description_->get_self_idx())};
}
private:
static const size_t MAX_REJECT_REASON_SIZE = 1024;
};
} // namespace validatorsession