1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 11:12:16 +00:00

Accelerator, part 1 (#1119)

This commit contains some parts of https://github.com/ton-blockchain/ton/tree/accelerator
This is auxiliary code that mostly does not change node behavior.

1) Semiprivate overlays and other improvements in overlays code
2) Rename actual_min_split -> monitor_min_split, fix building shard overlays
3) Loading block candidates by block id from DB, fix accept_block after validator restart
4) Cells: ProofStorageStat and changes in CellUsageTree
5) Remove some unused code, other minor changes
This commit is contained in:
SpyCheese 2024-08-23 11:46:40 +03:00 committed by GitHub
parent 9a10f79fba
commit 908415d00b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 2221 additions and 638 deletions

View file

@ -529,6 +529,8 @@ target_link_libraries(test-rldp2 adnl adnltest dht rldp2 tl_api)
add_executable(test-validator-session-state test/test-validator-session-state.cpp) add_executable(test-validator-session-state test/test-validator-session-state.cpp)
target_link_libraries(test-validator-session-state adnl dht rldp validatorsession tl_api) target_link_libraries(test-validator-session-state adnl dht rldp validatorsession tl_api)
add_executable(test-overlay test/test-overlay.cpp)
target_link_libraries(test-overlay overlay tdutils tdactor adnl adnltest tl_api dht )
add_executable(test-catchain test/test-catchain.cpp) add_executable(test-catchain test/test-catchain.cpp)
target_link_libraries(test-catchain overlay tdutils tdactor adnl adnltest rldp tl_api dht target_link_libraries(test-catchain overlay tdutils tdactor adnl adnltest rldp tl_api dht
catchain ) catchain )

View file

@ -25,7 +25,7 @@ namespace ton {
namespace adnl { namespace adnl {
void AdnlQuery::alarm() { void AdnlQuery::alarm() {
set_error(td::Status::Error(ErrorCode::timeout, "adnl query timeout")); set_error(td::Status::Error(ErrorCode::timeout, PSTRING() << "timeout for adnl query " << name_));
} }
void AdnlQuery::result(td::BufferSlice data) { void AdnlQuery::result(td::BufferSlice data) {
promise_.set_value(std::move(data)); promise_.set_value(std::move(data));

View file

@ -666,15 +666,15 @@ wc_split_merge_timings#0
//workchain#a5 enabled_since:uint32 min_split:(## 8) max_split:(## 8) //workchain#a5 enabled_since:uint32 min_split:(## 8) max_split:(## 8)
// { min_split <= max_split } { max_split <= 60 } // { min_split <= max_split } { max_split <= 60 }
workchain#a6 enabled_since:uint32 actual_min_split:(## 8) workchain#a6 enabled_since:uint32 monitor_min_split:(## 8)
min_split:(## 8) max_split:(## 8) { actual_min_split <= min_split } min_split:(## 8) max_split:(## 8) { monitor_min_split <= min_split }
basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 } basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 }
zerostate_root_hash:bits256 zerostate_file_hash:bits256 zerostate_root_hash:bits256 zerostate_file_hash:bits256
version:uint32 format:(WorkchainFormat basic) version:uint32 format:(WorkchainFormat basic)
= WorkchainDescr; = WorkchainDescr;
workchain_v2#a7 enabled_since:uint32 actual_min_split:(## 8) workchain_v2#a7 enabled_since:uint32 monitor_min_split:(## 8)
min_split:(## 8) max_split:(## 8) { actual_min_split <= min_split } min_split:(## 8) max_split:(## 8) { monitor_min_split <= min_split }
basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 } basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 }
zerostate_root_hash:bits256 zerostate_file_hash:bits256 zerostate_root_hash:bits256 zerostate_file_hash:bits256
version:uint32 format:(WorkchainFormat basic) version:uint32 format:(WorkchainFormat basic)

View file

@ -2075,7 +2075,7 @@ bool WorkchainInfo::unpack(ton::WorkchainId wc, vm::CellSlice& cs) {
} }
auto unpack_v1 = [this](auto& info) { auto unpack_v1 = [this](auto& info) {
enabled_since = info.enabled_since; enabled_since = info.enabled_since;
actual_min_split = info.actual_min_split; monitor_min_split = info.monitor_min_split;
min_split = info.min_split; min_split = info.min_split;
max_split = info.max_split; max_split = info.max_split;
basic = info.basic; basic = info.basic;

View file

@ -414,7 +414,7 @@ struct CatchainValidatorsConfig {
struct WorkchainInfo : public td::CntObject { struct WorkchainInfo : public td::CntObject {
ton::WorkchainId workchain{ton::workchainInvalid}; ton::WorkchainId workchain{ton::workchainInvalid};
ton::UnixTime enabled_since; ton::UnixTime enabled_since;
td::uint32 actual_min_split; td::uint32 monitor_min_split;
td::uint32 min_split, max_split; td::uint32 min_split, max_split;
bool basic; bool basic;
bool active; bool active;

View file

@ -1214,4 +1214,35 @@ bool VmStorageStat::add_storage(const CellSlice& cs) {
return true; return true;
} }
static td::uint64 estimate_prunned_size() {
return 41;
}
static td::uint64 estimate_serialized_size(const Ref<DataCell>& cell) {
return cell->get_serialized_size() + cell->size_refs() * 3 + 3;
}
void ProofStorageStat::add_cell(const Ref<DataCell>& cell) {
auto& status = cells_[cell->get_hash()];
if (status == c_loaded) {
return;
}
if (status == c_prunned) {
proof_size_ -= estimate_prunned_size();
}
status = c_loaded;
proof_size_ += estimate_serialized_size(cell);
for (unsigned i = 0; i < cell->size_refs(); ++i) {
auto& child_status = cells_[cell->get_ref(i)->get_hash()];
if (child_status == c_none) {
child_status = c_prunned;
proof_size_ += estimate_prunned_size();
}
}
}
td::uint64 ProofStorageStat::estimate_proof_size() const {
return proof_size_;
}
} // namespace vm } // namespace vm

View file

@ -163,6 +163,18 @@ struct VmStorageStat {
} }
}; };
class ProofStorageStat {
public:
void add_cell(const Ref<DataCell>& cell);
td::uint64 estimate_proof_size() const;
private:
enum CellStatus {
c_none = 0, c_prunned = 1, c_loaded = 2
};
std::map<vm::Cell::Hash, CellStatus> cells_;
td::uint64 proof_size_ = 0;
};
struct CellSerializationInfo { struct CellSerializationInfo {
bool special; bool special;
Cell::LevelMask level_mask; Cell::LevelMask level_mask;

View file

@ -22,12 +22,12 @@ namespace vm {
// //
// CellUsageTree::NodePtr // CellUsageTree::NodePtr
// //
bool CellUsageTree::NodePtr::on_load() const { bool CellUsageTree::NodePtr::on_load(const td::Ref<vm::DataCell>& cell) const {
auto tree = tree_weak_.lock(); auto tree = tree_weak_.lock();
if (!tree) { if (!tree) {
return false; return false;
} }
tree->on_load(node_id_); tree->on_load(node_id_, cell);
return true; return true;
} }
@ -111,8 +111,14 @@ void CellUsageTree::set_use_mark_for_is_loaded(bool use_mark) {
use_mark_ = use_mark; use_mark_ = use_mark;
} }
void CellUsageTree::on_load(NodeId node_id) { void CellUsageTree::on_load(NodeId node_id, const td::Ref<vm::DataCell>& cell) {
if (nodes_[node_id].is_loaded) {
return;
}
nodes_[node_id].is_loaded = true; nodes_[node_id].is_loaded = true;
if (cell_load_callback_) {
cell_load_callback_(cell);
}
} }
CellUsageTree::NodeId CellUsageTree::create_child(NodeId node_id, unsigned ref_id) { CellUsageTree::NodeId CellUsageTree::create_child(NodeId node_id, unsigned ref_id) {

View file

@ -22,8 +22,12 @@
#include "td/utils/int_types.h" #include "td/utils/int_types.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include <functional>
namespace vm { namespace vm {
class DataCell;
class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> { class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
public: public:
using NodeId = td::uint32; using NodeId = td::uint32;
@ -38,7 +42,7 @@ class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
return node_id_ == 0 || tree_weak_.expired(); return node_id_ == 0 || tree_weak_.expired();
} }
bool on_load() const; bool on_load(const td::Ref<vm::DataCell>& cell) const;
NodePtr create_child(unsigned ref_id) const; NodePtr create_child(unsigned ref_id) const;
bool mark_path(CellUsageTree* master_tree) const; bool mark_path(CellUsageTree* master_tree) const;
bool is_from_tree(const CellUsageTree* master_tree) const; bool is_from_tree(const CellUsageTree* master_tree) const;
@ -59,6 +63,10 @@ class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
void set_use_mark_for_is_loaded(bool use_mark = true); void set_use_mark_for_is_loaded(bool use_mark = true);
NodeId create_child(NodeId node_id, unsigned ref_id); NodeId create_child(NodeId node_id, unsigned ref_id);
void set_cell_load_callback(std::function<void(const td::Ref<vm::DataCell>&)> f) {
cell_load_callback_ = std::move(f);
}
private: private:
struct Node { struct Node {
bool is_loaded{false}; bool is_loaded{false};
@ -68,8 +76,9 @@ class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
}; };
bool use_mark_{false}; bool use_mark_{false};
std::vector<Node> nodes_{2}; std::vector<Node> nodes_{2};
std::function<void(const td::Ref<vm::DataCell>&)> cell_load_callback_;
void on_load(NodeId node_id); void on_load(NodeId node_id, const td::Ref<vm::DataCell>& cell);
NodeId create_node(NodeId parent); NodeId create_node(NodeId parent);
}; };
} // namespace vm } // namespace vm

View file

@ -66,6 +66,10 @@ class MerkleProofBuilder {
td::Result<Ref<Cell>> extract_proof() const; td::Result<Ref<Cell>> extract_proof() const;
bool extract_proof_to(Ref<Cell> &proof_root) const; bool extract_proof_to(Ref<Cell> &proof_root) const;
td::Result<td::BufferSlice> extract_proof_boc() const; td::Result<td::BufferSlice> extract_proof_boc() const;
void set_cell_load_callback(std::function<void(const td::Ref<vm::DataCell>&)> f) {
usage_tree->set_cell_load_callback(std::move(f));
}
}; };
} // namespace vm } // namespace vm

View file

@ -39,7 +39,7 @@ class UsageCell : public Cell {
// load interface // load interface
td::Result<LoadedCell> load_cell() const override { td::Result<LoadedCell> load_cell() const override {
TRY_RESULT(loaded_cell, cell_->load_cell()); TRY_RESULT(loaded_cell, cell_->load_cell());
if (tree_node_.on_load()) { if (tree_node_.on_load(loaded_cell.data_cell)) {
CHECK(loaded_cell.tree_node.empty()); CHECK(loaded_cell.tree_node.empty());
loaded_cell.tree_node = tree_node_; loaded_cell.tree_node = tree_node_;
} }

View file

@ -260,6 +260,10 @@ class PublicKey {
td::BufferSlice export_as_slice() const; td::BufferSlice export_as_slice() const;
static td::Result<PublicKey> import(td::Slice s); static td::Result<PublicKey> import(td::Slice s);
bool is_ed25519() const {
return pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>();
}
pubkeys::Ed25519 ed25519_value() const { pubkeys::Ed25519 ed25519_value() const {
CHECK(pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>()); CHECK(pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>());
return pub_key_.get<pubkeys::Ed25519>(); return pub_key_.get<pubkeys::Ed25519>();

View file

@ -68,7 +68,7 @@ td::Status BroadcastSimple::run_checks() {
td::Status BroadcastSimple::distribute() { td::Status BroadcastSimple::distribute() {
auto B = serialize(); auto B = serialize();
auto nodes = overlay_->get_neighbours(3); auto nodes = overlay_->get_neighbours(overlay_->propagate_broadcast_to());
auto manager = overlay_->overlay_manager(); auto manager = overlay_->overlay_manager();
for (auto &n : nodes) { for (auto &n : nodes) {
@ -115,7 +115,8 @@ td::Status BroadcastSimple::run() {
return run_continue(); return run_continue();
} }
td::Status BroadcastSimple::create(OverlayImpl *overlay, adnl::AdnlNodeIdShort src_peer_id, tl_object_ptr<ton_api::overlay_broadcast> broadcast) { td::Status BroadcastSimple::create(OverlayImpl *overlay, adnl::AdnlNodeIdShort src_peer_id,
tl_object_ptr<ton_api::overlay_broadcast> broadcast) {
auto src = PublicKey{broadcast->src_}; auto src = PublicKey{broadcast->src_};
auto data_hash = sha256_bits256(broadcast->data_.as_slice()); auto data_hash = sha256_bits256(broadcast->data_.as_slice());
auto broadcast_hash = compute_broadcast_id(src, data_hash, broadcast->flags_); auto broadcast_hash = compute_broadcast_id(src, data_hash, broadcast->flags_);

View file

@ -112,7 +112,7 @@ td::Status BroadcastFec::distribute_part(td::uint32 seqno) {
td::BufferSlice data_short = std::move(tls.first); td::BufferSlice data_short = std::move(tls.first);
td::BufferSlice data = std::move(tls.second); td::BufferSlice data = std::move(tls.second);
auto nodes = overlay_->get_neighbours(5); auto nodes = overlay_->get_neighbours(overlay_->propagate_broadcast_to());
auto manager = overlay_->overlay_manager(); auto manager = overlay_->overlay_manager();
for (auto &n : nodes) { for (auto &n : nodes) {

View file

@ -21,8 +21,14 @@
#include "auto/tl/ton_api.h" #include "auto/tl/ton_api.h"
#include "adnl/adnl-node-id.hpp" #include "adnl/adnl-node-id.hpp"
#include "overlay/overlays.h" #include "overlay/overlays.h"
#include "td/utils/SharedSlice.h"
#include "td/utils/buffer.h"
#include "td/utils/overloaded.h" #include "td/utils/overloaded.h"
#include "keys/encryptor.h" #include "keys/encryptor.h"
#include "td/utils/port/StdStreams.h"
#include "td/utils/unique_ptr.h"
#include <limits>
#include <memory>
namespace ton { namespace ton {
@ -30,18 +36,30 @@ namespace overlay {
class OverlayNode { class OverlayNode {
public: public:
explicit OverlayNode(adnl::AdnlNodeIdShort self_id, OverlayIdShort overlay) { explicit OverlayNode(adnl::AdnlNodeIdShort self_id, OverlayIdShort overlay, td::uint32 flags) {
source_ = self_id; source_ = self_id;
overlay_ = overlay; overlay_ = overlay;
flags_ = flags;
version_ = static_cast<td::int32>(td::Clocks::system()); version_ = static_cast<td::int32>(td::Clocks::system());
} }
static td::Result<OverlayNode> create(const tl_object_ptr<ton_api::overlay_node> &node) { static td::Result<OverlayNode> create(const tl_object_ptr<ton_api::overlay_node> &node) {
TRY_RESULT(source, adnl::AdnlNodeIdFull::create(node->id_)); TRY_RESULT(source, adnl::AdnlNodeIdFull::create(node->id_));
return OverlayNode{source, OverlayIdShort{node->overlay_}, node->version_, node->signature_.as_slice()}; return OverlayNode{source, OverlayIdShort{node->overlay_}, 0, node->version_, node->signature_.as_slice()};
} }
OverlayNode(td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source, OverlayIdShort overlay, static td::Result<OverlayNode> create(const tl_object_ptr<ton_api::overlay_nodeV2> &node) {
TRY_RESULT(source, adnl::AdnlNodeIdFull::create(node->id_));
auto res = OverlayNode{source, OverlayIdShort{node->overlay_}, (td::uint32)node->flags_, node->version_,
node->signature_.as_slice()};
res.update_certificate(OverlayMemberCertificate(node->certificate_.get()));
return res;
}
OverlayNode(td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source, OverlayIdShort overlay, td::uint32 flags,
td::int32 version, td::Slice signature) td::int32 version, td::Slice signature)
: source_(std::move(source)), overlay_(overlay), version_(version), signature_(td::SharedSlice(signature)) { : source_(std::move(source))
, overlay_(overlay)
, flags_(flags)
, version_(version)
, signature_(td::SharedSlice(signature)) {
} }
OverlayNode(td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source, OverlayIdShort overlay, OverlayNode(td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source, OverlayIdShort overlay,
td::int32 version, td::SharedSlice signature) td::int32 version, td::SharedSlice signature)
@ -64,10 +82,17 @@ class OverlayNode {
} }
td::BufferSlice to_sign() const { td::BufferSlice to_sign() const {
auto obj = create_tl_object<ton_api::overlay_node_toSign>(nullptr, overlay_.tl(), version_); if (flags_ == 0) {
source_.visit(td::overloaded([&](const adnl::AdnlNodeIdShort &id) { obj->id_ = id.tl(); }, auto obj = create_tl_object<ton_api::overlay_node_toSign>(nullptr, overlay_.tl(), version_);
[&](const adnl::AdnlNodeIdFull &id) { obj->id_ = id.compute_short_id().tl(); })); source_.visit(td::overloaded([&](const adnl::AdnlNodeIdShort &id) { obj->id_ = id.tl(); },
return serialize_tl_object(obj, true); [&](const adnl::AdnlNodeIdFull &id) { obj->id_ = id.compute_short_id().tl(); }));
return serialize_tl_object(obj, true);
} else {
auto obj = create_tl_object<ton_api::overlay_node_toSignEx>(nullptr, overlay_.tl(), flags_, version_);
source_.visit(td::overloaded([&](const adnl::AdnlNodeIdShort &id) { obj->id_ = id.tl(); },
[&](const adnl::AdnlNodeIdFull &id) { obj->id_ = id.compute_short_id().tl(); }));
return serialize_tl_object(obj, true);
}
} }
void update_adnl_id(adnl::AdnlNodeIdFull node_id) { void update_adnl_id(adnl::AdnlNodeIdFull node_id) {
source_ = node_id; source_ = node_id;
@ -81,6 +106,9 @@ class OverlayNode {
td::int32 version() const { td::int32 version() const {
return version_; return version_;
} }
td::uint32 flags() const {
return flags_;
}
td::BufferSlice signature() const { td::BufferSlice signature() const {
return signature_.clone_as_buffer_slice(); return signature_.clone_as_buffer_slice();
} }
@ -103,15 +131,69 @@ class OverlayNode {
[&](const adnl::AdnlNodeIdFull &id) { obj->id_ = id.tl(); })); [&](const adnl::AdnlNodeIdFull &id) { obj->id_ = id.tl(); }));
return obj; return obj;
} }
tl_object_ptr<ton_api::overlay_nodeV2> tl_v2() const {
tl_object_ptr<ton_api::overlay_MemberCertificate> cert;
if (cert_ && !cert_->empty()) {
cert = cert_->tl();
} else {
cert = create_tl_object<ton_api::overlay_emptyMemberCertificate>();
}
auto obj = create_tl_object<ton_api::overlay_nodeV2>(nullptr, overlay_.tl(), flags_, version_,
signature_.clone_as_buffer_slice(), std::move(cert));
source_.visit(td::overloaded([&](const adnl::AdnlNodeIdShort &id) { UNREACHABLE(); },
[&](const adnl::AdnlNodeIdFull &id) { obj->id_ = id.tl(); }));
return obj;
}
OverlayNode clone() const { OverlayNode clone() const {
return OverlayNode{source_, overlay_, version_, signature_.clone()}; auto res = OverlayNode{source_, overlay_, version_, signature_.clone()};
if (cert_) {
res.cert_ = td::make_unique<OverlayMemberCertificate>(*cert_);
}
return res;
}
const OverlayMemberCertificate *certificate() const {
if (cert_) {
return cert_.get();
}
return &empty_certificate_;
}
void update_certificate(OverlayMemberCertificate cert) {
if (!cert_ || cert_->empty() || cert_->is_expired() || cert.is_newer(*cert_)) {
cert_ = td::make_unique<OverlayMemberCertificate>(std::move(cert));
}
}
void update(OverlayNode from) {
if (version_ < from.version_) {
source_ = from.source_;
overlay_ = from.overlay_;
flags_ = from.flags_;
version_ = from.version_;
signature_ = from.signature_.clone();
}
if (from.cert_ && !from.cert_->empty()) {
update_certificate(std::move(*from.cert_));
}
}
void clear_certificate() {
cert_ = nullptr;
}
bool has_full_id() const {
return source_.get_offset() == source_.offset<adnl::AdnlNodeIdFull>();
} }
private: private:
td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source_; td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source_;
OverlayIdShort overlay_; OverlayIdShort overlay_;
td::uint32 flags_;
td::int32 version_; td::int32 version_;
td::unique_ptr<OverlayMemberCertificate> cert_;
td::SharedSlice signature_; td::SharedSlice signature_;
static const OverlayMemberCertificate empty_certificate_;
}; };
} // namespace overlay } // namespace overlay

View file

@ -18,6 +18,7 @@
*/ */
#include "overlay-manager.h" #include "overlay-manager.h"
#include "auto/tl/ton_api.h" #include "auto/tl/ton_api.h"
#include "auto/tl/ton_api.hpp"
#include "overlay.h" #include "overlay.h"
#include "adnl/utils.hpp" #include "adnl/utils.hpp"
@ -28,9 +29,9 @@
#include "td/db/RocksDb.h" #include "td/db/RocksDb.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include "td/utils/buffer.h"
#include "td/utils/overloaded.h" #include "td/utils/overloaded.h"
#include "keys/encryptor.h"
#include "td/utils/port/Poll.h" #include "td/utils/port/Poll.h"
#include <vector> #include <vector>
@ -42,13 +43,13 @@ void OverlayManager::update_dht_node(td::actor::ActorId<dht::Dht> dht) {
dht_node_ = dht; dht_node_ = dht;
for (auto &X : overlays_) { for (auto &X : overlays_) {
for (auto &Y : X.second) { for (auto &Y : X.second) {
td::actor::send_closure(Y.second, &Overlay::update_dht_node, dht); td::actor::send_closure(Y.second.overlay, &Overlay::update_dht_node, dht);
} }
} }
} }
void OverlayManager::register_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, void OverlayManager::register_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
td::actor::ActorOwn<Overlay> overlay) { OverlayMemberCertificate cert, td::actor::ActorOwn<Overlay> overlay) {
auto it = overlays_.find(local_id); auto it = overlays_.find(local_id);
VLOG(OVERLAY_INFO) << this << ": registering overlay " << overlay_id << "@" << local_id; VLOG(OVERLAY_INFO) << this << ": registering overlay " << overlay_id << "@" << local_id;
if (it == overlays_.end()) { if (it == overlays_.end()) {
@ -58,19 +59,34 @@ void OverlayManager::register_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdS
td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id, td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id,
adnl::Adnl::int_to_bytestring(ton_api::overlay_query::ID), adnl::Adnl::int_to_bytestring(ton_api::overlay_query::ID),
std::make_unique<AdnlCallback>(actor_id(this))); std::make_unique<AdnlCallback>(actor_id(this)));
td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id,
adnl::Adnl::int_to_bytestring(ton_api::overlay_messageWithExtra::ID),
std::make_unique<AdnlCallback>(actor_id(this)));
td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id,
adnl::Adnl::int_to_bytestring(ton_api::overlay_queryWithExtra::ID),
std::make_unique<AdnlCallback>(actor_id(this)));
} }
overlays_[local_id][overlay_id] = std::move(overlay); overlays_[local_id][overlay_id] = OverlayDescription{std::move(overlay), std::move(cert)};
auto P = td::PromiseCreator::lambda([id = overlays_[local_id][overlay_id].get()](td::Result<DbType::GetResult> R) { auto P =
R.ensure(); td::PromiseCreator::lambda([id = overlays_[local_id][overlay_id].overlay.get()](td::Result<DbType::GetResult> R) {
auto value = R.move_as_ok(); R.ensure();
if (value.status == td::KeyValue::GetStatus::Ok) { auto value = R.move_as_ok();
auto F = fetch_tl_object<ton_api::overlay_db_nodes>(std::move(value.value), true); if (value.status == td::KeyValue::GetStatus::Ok) {
F.ensure(); auto F = fetch_tl_object<ton_api::overlay_db_Nodes>(std::move(value.value), true);
auto nodes = std::move(F.move_as_ok()->nodes_); F.ensure();
td::actor::send_closure(id, &Overlay::receive_nodes_from_db, std::move(nodes)); ton_api::downcast_call(
} *F.move_as_ok(), td::overloaded(
}); [&](ton_api::overlay_db_nodes &V) {
auto nodes = std::move(V.nodes_);
td::actor::send_closure(id, &Overlay::receive_nodes_from_db, std::move(nodes));
},
[&](ton_api::overlay_db_nodesV2 &V) {
auto nodes = std::move(V.nodes_);
td::actor::send_closure(id, &Overlay::receive_nodes_from_db_v2, std::move(nodes));
}));
}
});
auto key = create_hash_tl_object<ton_api::overlay_db_key_nodes>(local_id.bits256_value(), overlay_id.bits256_value()); auto key = create_hash_tl_object<ton_api::overlay_db_key_nodes>(local_id.bits256_value(), overlay_id.bits256_value());
db_.get(key, std::move(P)); db_.get(key, std::move(P));
} }
@ -84,6 +100,10 @@ void OverlayManager::delete_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdSho
adnl::Adnl::int_to_bytestring(ton_api::overlay_message::ID)); adnl::Adnl::int_to_bytestring(ton_api::overlay_message::ID));
td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id, td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id,
adnl::Adnl::int_to_bytestring(ton_api::overlay_query::ID)); adnl::Adnl::int_to_bytestring(ton_api::overlay_query::ID));
td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id,
adnl::Adnl::int_to_bytestring(ton_api::overlay_messageWithExtra::ID));
td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id,
adnl::Adnl::int_to_bytestring(ton_api::overlay_queryWithExtra::ID));
overlays_.erase(it); overlays_.erase(it);
} }
} }
@ -101,74 +121,113 @@ void OverlayManager::create_public_overlay_ex(adnl::AdnlNodeIdShort local_id, Ov
td::string scope, OverlayOptions opts) { td::string scope, OverlayOptions opts) {
CHECK(!dht_node_.empty()); CHECK(!dht_node_.empty());
auto id = overlay_id.compute_short_id(); auto id = overlay_id.compute_short_id();
register_overlay(local_id, id, register_overlay(local_id, id, OverlayMemberCertificate{},
Overlay::create(keyring_, adnl_, actor_id(this), dht_node_, local_id, std::move(overlay_id), Overlay::create_public(keyring_, adnl_, actor_id(this), dht_node_, local_id, std::move(overlay_id),
std::move(callback), std::move(rules), scope, std::move(opts))); std::move(callback), std::move(rules), scope, std::move(opts)));
} }
void OverlayManager::create_private_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, void OverlayManager::create_private_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<adnl::AdnlNodeIdShort> nodes,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, std::unique_ptr<Callback> callback, OverlayPrivacyRules rules,
std::string scope) { std::string scope) {
create_private_overlay_ex(local_id, std::move(overlay_id), std::move(nodes), std::move(callback), std::move(rules),
std::move(scope), {});
}
void OverlayManager::create_private_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules,
std::string scope, OverlayOptions opts) {
auto id = overlay_id.compute_short_id(); auto id = overlay_id.compute_short_id();
register_overlay(local_id, id, register_overlay(local_id, id, OverlayMemberCertificate{},
Overlay::create(keyring_, adnl_, actor_id(this), dht_node_, local_id, std::move(overlay_id), Overlay::create_private(keyring_, adnl_, actor_id(this), dht_node_, local_id, std::move(overlay_id),
std::move(nodes), std::move(callback), std::move(rules), std::move(scope))); std::move(nodes), std::move(callback), std::move(rules), std::move(scope),
std::move(opts)));
}
void OverlayManager::create_semiprivate_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes,
std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate certificate,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules,
td::string scope, OverlayOptions opts) {
auto id = overlay_id.compute_short_id();
register_overlay(
local_id, id, certificate,
Overlay::create_semiprivate(keyring_, adnl_, actor_id(this), dht_node_, local_id, std::move(overlay_id),
std::move(nodes), std::move(root_public_keys), certificate, std::move(callback),
std::move(rules), std::move(scope), std::move(opts)));
} }
void OverlayManager::receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) { void OverlayManager::receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) {
auto R = fetch_tl_prefix<ton_api::overlay_message>(data, true); OverlayIdShort overlay_id;
tl_object_ptr<ton_api::overlay_messageExtra> extra;
if (R.is_error()) { auto R = fetch_tl_prefix<ton_api::overlay_messageWithExtra>(data, true);
VLOG(OVERLAY_WARNING) << this << ": can not parse overlay message: " << R.move_as_error(); if (R.is_ok()) {
return; overlay_id = OverlayIdShort{R.ok()->overlay_};
extra = std::move(R.ok()->extra_);
} else {
auto R2 = fetch_tl_prefix<ton_api::overlay_message>(data, true);
if (R2.is_ok()) {
overlay_id = OverlayIdShort{R2.ok()->overlay_};
} else {
VLOG(OVERLAY_WARNING) << this << ": can not parse overlay message [" << src << "->" << dst
<< "]: " << R2.move_as_error();
return;
}
} }
auto M = R.move_as_ok();
auto it = overlays_.find(dst); auto it = overlays_.find(dst);
if (it == overlays_.end()) { if (it == overlays_.end()) {
VLOG(OVERLAY_NOTICE) << this << ": message to unknown overlay " << M->overlay_ << "@" << dst; VLOG(OVERLAY_NOTICE) << this << ": message to unknown overlay " << overlay_id << "@" << dst;
return; return;
} }
auto it2 = it->second.find(OverlayIdShort{M->overlay_}); auto it2 = it->second.find(overlay_id);
if (it2 == it->second.end()) { if (it2 == it->second.end()) {
VLOG(OVERLAY_NOTICE) << this << ": message to localid is not in overlay " << M->overlay_ << "@" << dst; VLOG(OVERLAY_NOTICE) << this << ": message to localid is not in overlay " << overlay_id << "@" << dst;
return; return;
} }
td::actor::send_closure(it2->second, &Overlay::update_throughput_in_ctr, src, (td::uint32)data.size(), false); td::actor::send_closure(it2->second.overlay, &Overlay::update_throughput_in_ctr, src, (td::uint32)data.size(), false);
td::actor::send_closure(it2->second, &Overlay::receive_message, src, std::move(data)); td::actor::send_closure(it2->second.overlay, &Overlay::receive_message, src, std::move(extra), std::move(data));
} }
void OverlayManager::receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data, void OverlayManager::receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) { td::Promise<td::BufferSlice> promise) {
auto R = fetch_tl_prefix<ton_api::overlay_query>(data, true); OverlayIdShort overlay_id;
tl_object_ptr<ton_api::overlay_messageExtra> extra;
if (R.is_error()) { auto R = fetch_tl_prefix<ton_api::overlay_queryWithExtra>(data, true);
VLOG(OVERLAY_WARNING) << this << ": can not parse overlay query [" << src << "->" << dst if (R.is_ok()) {
<< "]: " << R.move_as_error(); overlay_id = OverlayIdShort{R.ok()->overlay_};
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "bad overlay query header")); extra = std::move(R.ok()->extra_);
return; } else {
auto R2 = fetch_tl_prefix<ton_api::overlay_query>(data, true);
if (R2.is_ok()) {
overlay_id = OverlayIdShort{R2.ok()->overlay_};
} else {
VLOG(OVERLAY_WARNING) << this << ": can not parse overlay query [" << src << "->" << dst
<< "]: " << R2.move_as_error();
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "bad overlay query header"));
return;
}
} }
auto M = R.move_as_ok();
auto it = overlays_.find(dst); auto it = overlays_.find(dst);
if (it == overlays_.end()) { if (it == overlays_.end()) {
VLOG(OVERLAY_NOTICE) << this << ": query to unknown overlay " << M->overlay_ << "@" << dst << " from " << src; VLOG(OVERLAY_NOTICE) << this << ": query to unknown overlay " << overlay_id << "@" << dst << " from " << src;
promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad local_id " << dst)); promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad local_id " << dst));
return; return;
} }
auto it2 = it->second.find(OverlayIdShort{M->overlay_}); auto it2 = it->second.find(overlay_id);
if (it2 == it->second.end()) { if (it2 == it->second.end()) {
VLOG(OVERLAY_NOTICE) << this << ": query to localid not in overlay " << M->overlay_ << "@" << dst << " from " << src; VLOG(OVERLAY_NOTICE) << this << ": query to localid not in overlay " << overlay_id << "@" << dst << " from " << src;
promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad overlay_id " << M->overlay_)); promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad overlay_id " << overlay_id));
return; return;
} }
td::actor::send_closure(it2->second, &Overlay::update_throughput_in_ctr, src, (td::uint32)data.size(), true); td::actor::send_closure(it2->second.overlay, &Overlay::update_throughput_in_ctr, src, (td::uint32)data.size(), true);
td::actor::send_closure(it2->second, &Overlay::receive_query, src, std::move(data), std::move(promise)); td::actor::send_closure(it2->second.overlay, &Overlay::receive_query, src, std::move(extra), std::move(data),
std::move(promise));
} }
void OverlayManager::send_query_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, void OverlayManager::send_query_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
@ -176,35 +235,64 @@ void OverlayManager::send_query_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdS
td::BufferSlice query, td::uint64 max_answer_size, td::BufferSlice query, td::uint64 max_answer_size,
td::actor::ActorId<adnl::AdnlSenderInterface> via) { td::actor::ActorId<adnl::AdnlSenderInterface> via) {
CHECK(query.size() <= adnl::Adnl::huge_packet_max_size()); CHECK(query.size() <= adnl::Adnl::huge_packet_max_size());
auto extra = create_tl_object<ton_api::overlay_messageExtra>();
extra->flags_ = 0;
auto it = overlays_.find(src); auto it = overlays_.find(src);
if (it != overlays_.end()) { if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id); auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) { if (it2 != it->second.end()) {
td::actor::send_closure(it2->second, &Overlay::update_throughput_out_ctr, dst, (td::uint32)query.size(), true); td::actor::send_closure(it2->second.overlay, &Overlay::update_throughput_out_ctr, dst, (td::uint32)query.size(),
true);
if (!it2->second.member_certificate.empty()) {
extra->flags_ |= 1;
extra->certificate_ = it2->second.member_certificate.tl();
}
} }
} }
td::actor::send_closure( auto extra_flags = extra->flags_;
via, &adnl::AdnlSenderInterface::send_query_ex, src, dst, std::move(name), std::move(promise), timeout, td::BufferSlice serialized_query =
create_serialize_tl_object_suffix<ton_api::overlay_query>(query.as_slice(), overlay_id.tl()), max_answer_size); (extra_flags ? create_serialize_tl_object_suffix<ton_api::overlay_queryWithExtra>(
query.as_slice(), overlay_id.tl(), std::move(extra))
: create_serialize_tl_object_suffix<ton_api::overlay_query>(query.as_slice(), overlay_id.tl()));
td::actor::send_closure(via, &adnl::AdnlSenderInterface::send_query_ex, src, dst, std::move(name), std::move(promise),
timeout, std::move(serialized_query), max_answer_size);
} }
void OverlayManager::send_message_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, void OverlayManager::send_message_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
td::BufferSlice object, td::actor::ActorId<adnl::AdnlSenderInterface> via) { td::BufferSlice object, td::actor::ActorId<adnl::AdnlSenderInterface> via) {
CHECK(object.size() <= adnl::Adnl::huge_packet_max_size()); CHECK(object.size() <= adnl::Adnl::huge_packet_max_size());
auto extra = create_tl_object<ton_api::overlay_messageExtra>();
extra->flags_ = 0;
auto it = overlays_.find(src); auto it = overlays_.find(src);
if (it != overlays_.end()) { if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id); auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) { if (it2 != it->second.end()) {
td::actor::send_closure(it2->second, &Overlay::update_throughput_out_ctr, dst, (td::uint32)object.size(), false); td::actor::send_closure(it2->second.overlay, &Overlay::update_throughput_out_ctr, dst, (td::uint32)object.size(),
false);
if (!it2->second.member_certificate.empty()) {
// do not send certificate here, we hope that all our neighbours already know of out certificate
// we send it every second to some random nodes. Here we don't want to increase the size of the message
if (false) {
extra->flags_ |= 1;
extra->certificate_ = it2->second.member_certificate.tl();
}
}
} }
} }
td::actor::send_closure( auto extra_flags = extra->flags_;
via, &adnl::AdnlSenderInterface::send_message, src, dst, td::BufferSlice serialized_message =
create_serialize_tl_object_suffix<ton_api::overlay_message>(object.as_slice(), overlay_id.tl())); (extra_flags ? create_serialize_tl_object_suffix<ton_api::overlay_messageWithExtra>(
object.as_slice(), overlay_id.tl(), std::move(extra))
: create_serialize_tl_object_suffix<ton_api::overlay_message>(object.as_slice(), overlay_id.tl()));
td::actor::send_closure(via, &adnl::AdnlSenderInterface::send_message, src, dst, std::move(serialized_message));
} }
void OverlayManager::send_broadcast(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, td::BufferSlice object) { void OverlayManager::send_broadcast(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, td::BufferSlice object) {
@ -218,7 +306,7 @@ void OverlayManager::send_broadcast_ex(adnl::AdnlNodeIdShort local_id, OverlayId
if (it != overlays_.end()) { if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id); auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) { if (it2 != it->second.end()) {
td::actor::send_closure(it2->second, &Overlay::send_broadcast, send_as, flags, std::move(object)); td::actor::send_closure(it2->second.overlay, &Overlay::send_broadcast, send_as, flags, std::move(object));
} }
} }
} }
@ -235,7 +323,7 @@ void OverlayManager::send_broadcast_fec_ex(adnl::AdnlNodeIdShort local_id, Overl
if (it != overlays_.end()) { if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id); auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) { if (it2 != it->second.end()) {
td::actor::send_closure(it2->second, &Overlay::send_broadcast_fec, send_as, flags, std::move(object)); td::actor::send_closure(it2->second.overlay, &Overlay::send_broadcast_fec, send_as, flags, std::move(object));
} }
} }
} }
@ -246,7 +334,7 @@ void OverlayManager::set_privacy_rules(adnl::AdnlNodeIdShort local_id, OverlayId
if (it != overlays_.end()) { if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id); auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) { if (it2 != it->second.end()) {
td::actor::send_closure(it2->second, &Overlay::set_privacy_rules, std::move(rules)); td::actor::send_closure(it2->second.overlay, &Overlay::set_privacy_rules, std::move(rules));
} }
} }
} }
@ -257,7 +345,34 @@ void OverlayManager::update_certificate(adnl::AdnlNodeIdShort local_id, OverlayI
if (it != overlays_.end()) { if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id); auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) { if (it2 != it->second.end()) {
td::actor::send_closure(it2->second, &Overlay::add_certificate, key, std::move(cert)); td::actor::send_closure(it2->second.overlay, &Overlay::add_certificate, key, std::move(cert));
}
}
}
void OverlayManager::update_member_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
OverlayMemberCertificate certificate) {
auto it = overlays_.find(local_id);
if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) {
it2->second.member_certificate = certificate;
td::actor::send_closure(it2->second.overlay, &Overlay::update_member_certificate, certificate);
}
}
}
void OverlayManager::update_root_member_list(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes,
std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate certificate) {
auto it = overlays_.find(local_id);
if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) {
it2->second.member_certificate = certificate;
td::actor::send_closure(it2->second.overlay, &Overlay::update_root_member_list, std::move(nodes),
std::move(root_public_keys), std::move(certificate));
} }
} }
} }
@ -266,12 +381,16 @@ void OverlayManager::get_overlay_random_peers(adnl::AdnlNodeIdShort local_id, Ov
td::uint32 max_peers, td::uint32 max_peers,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) { td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) {
auto it = overlays_.find(local_id); auto it = overlays_.find(local_id);
if (it != overlays_.end()) { if (it == overlays_.end()) {
auto it2 = it->second.find(overlay_id); promise.set_error(td::Status::Error(PSTRING() << "no such local id " << local_id));
if (it2 != it->second.end()) { return;
td::actor::send_closure(it2->second, &Overlay::get_overlay_random_peers, max_peers, std::move(promise));
}
} }
auto it2 = it->second.find(overlay_id);
if (it2 == it->second.end()) {
promise.set_error(td::Status::Error(PSTRING() << "no such overlay " << overlay_id));
return;
}
td::actor::send_closure(it2->second.overlay, &Overlay::get_overlay_random_peers, max_peers, std::move(promise));
} }
td::actor::ActorOwn<Overlays> Overlays::create(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorOwn<Overlays> Overlays::create(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
@ -334,7 +453,7 @@ void OverlayManager::get_stats(td::Promise<tl_object_ptr<ton_api::engine_validat
for (auto &a : overlays_) { for (auto &a : overlays_) {
for (auto &b : a.second) { for (auto &b : a.second) {
td::actor::send_closure(act, &Cb::incr_pending); td::actor::send_closure(act, &Cb::incr_pending);
td::actor::send_closure(b.second, &Overlay::get_stats, td::actor::send_closure(b.second.overlay, &Overlay::get_stats,
[act](td::Result<tl_object_ptr<ton_api::engine_validator_overlayStats>> R) { [act](td::Result<tl_object_ptr<ton_api::engine_validator_overlayStats>> R) {
if (R.is_ok()) { if (R.is_ok()) {
td::actor::send_closure(act, &Cb::receive_answer, R.move_as_ok()); td::actor::send_closure(act, &Cb::receive_answer, R.move_as_ok());
@ -348,6 +467,19 @@ void OverlayManager::get_stats(td::Promise<tl_object_ptr<ton_api::engine_validat
td::actor::send_closure(act, &Cb::decr_pending); td::actor::send_closure(act, &Cb::decr_pending);
} }
void OverlayManager::forget_peer(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay,
adnl::AdnlNodeIdShort peer_id) {
auto it = overlays_.find(local_id);
if (it == overlays_.end()) {
return;
}
auto it2 = it->second.find(overlay);
if (it2 == it->second.end()) {
return;
}
td::actor::send_closure(it2->second.overlay, &Overlay::forget_peer, peer_id);
}
Certificate::Certificate(PublicKey issued_by, td::int32 expire_at, td::uint32 max_size, td::uint32 flags, Certificate::Certificate(PublicKey issued_by, td::int32 expire_at, td::uint32 max_size, td::uint32 flags,
td::BufferSlice signature) td::BufferSlice signature)
: issued_by_(issued_by) : issued_by_(issued_by)
@ -454,6 +586,35 @@ tl_object_ptr<ton_api::overlay_Certificate> Certificate::empty_tl() {
return create_tl_object<ton_api::overlay_emptyCertificate>(); return create_tl_object<ton_api::overlay_emptyCertificate>();
} }
OverlayMemberCertificate::OverlayMemberCertificate(const ton_api::overlay_MemberCertificate *cert) {
if (!cert) {
expire_at_ = std::numeric_limits<td::int32>::max();
return;
}
if (cert->get_id() == ton_api::overlay_emptyMemberCertificate::ID) {
expire_at_ = std::numeric_limits<td::int32>::max();
return;
}
CHECK(cert->get_id() == ton_api::overlay_memberCertificate::ID);
const auto *real_cert = static_cast<const ton_api::overlay_memberCertificate *>(cert);
signed_by_ = PublicKey(real_cert->issued_by_);
flags_ = real_cert->flags_;
slot_ = real_cert->slot_;
expire_at_ = real_cert->expire_at_;
signature_ = td::SharedSlice(real_cert->signature_.as_slice());
}
td::Status OverlayMemberCertificate::check_signature(const adnl::AdnlNodeIdShort &node) {
if (is_expired()) {
return td::Status::Error(ErrorCode::notready, "certificate is expired");
}
td::BufferSlice data_to_sign = to_sign_data(node);
TRY_RESULT(encryptor, signed_by_.create_encryptor());
TRY_STATUS(encryptor->check_signature(data_to_sign.as_slice(), signature_.as_slice()));
return td::Status::OK();
}
} // namespace overlay } // namespace overlay
} // namespace ton } // namespace ton

View file

@ -53,11 +53,19 @@ class OverlayManager : public Overlays {
void create_public_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, void create_public_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope) override; std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope) override;
void create_public_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, void create_public_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope, std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope,
OverlayOptions opts) override; OverlayOptions opts) override;
void create_semiprivate_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate certificate,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope,
OverlayOptions opts) override;
void create_private_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, void create_private_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback, std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback,
OverlayPrivacyRules rules, std::string scope) override; OverlayPrivacyRules rules, std::string scope) override;
void create_private_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback,
OverlayPrivacyRules rules, std::string scope, OverlayOptions opts) override;
void delete_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id) override; void delete_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id) override;
void send_query(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, std::string name, void send_query(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice query) override { td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice query) override {
@ -84,6 +92,11 @@ class OverlayManager : public Overlays {
void set_privacy_rules(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, OverlayPrivacyRules rules) override; void set_privacy_rules(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, OverlayPrivacyRules rules) override;
void update_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, PublicKeyHash key, void update_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, PublicKeyHash key,
std::shared_ptr<Certificate> cert) override; std::shared_ptr<Certificate> cert) override;
void update_member_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
OverlayMemberCertificate certificate) override;
void update_root_member_list(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate certificate) override;
void get_overlay_random_peers(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay, td::uint32 max_peers, void get_overlay_random_peers(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay, td::uint32 max_peers,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) override; td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) override;
@ -92,10 +105,12 @@ class OverlayManager : public Overlays {
td::Promise<td::BufferSlice> promise); td::Promise<td::BufferSlice> promise);
void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data); void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data);
void register_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, void register_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, OverlayMemberCertificate cert,
td::actor::ActorOwn<Overlay> overlay); td::actor::ActorOwn<Overlay> overlay);
void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_overlaysStats>> promise) override; void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_overlaysStats>> promise) override;
void forget_peer(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay, adnl::AdnlNodeIdShort peer_id) override;
struct PrintId {}; struct PrintId {};
PrintId print_id() const { PrintId print_id() const {
@ -103,7 +118,11 @@ class OverlayManager : public Overlays {
} }
private: private:
std::map<adnl::AdnlNodeIdShort, std::map<OverlayIdShort, td::actor::ActorOwn<Overlay>>> overlays_; struct OverlayDescription {
td::actor::ActorOwn<Overlay> overlay;
OverlayMemberCertificate member_certificate;
};
std::map<adnl::AdnlNodeIdShort, std::map<OverlayIdShort, OverlayDescription>> overlays_;
std::string db_root_; std::string db_root_;

View file

@ -16,89 +16,165 @@
Copyright 2017-2020 Telegram Systems LLP Copyright 2017-2020 Telegram Systems LLP
*/ */
#include "adnl/adnl-node-id.hpp"
#include "adnl/adnl-node.h"
#include "auto/tl/ton_api.h"
#include "overlay.hpp" #include "overlay.hpp"
#include "td/utils/Status.h"
#include "td/utils/Time.h"
#include "td/utils/port/signals.h"
#include <algorithm>
#include <vector>
namespace ton { namespace ton {
namespace overlay { namespace overlay {
void OverlayImpl::del_peer(adnl::AdnlNodeIdShort id) { void OverlayImpl::del_peer(const adnl::AdnlNodeIdShort &id) {
auto P = peers_.get(id); auto P = peer_list_.peers_.get(id);
CHECK(P != nullptr); if (P == nullptr) {
return;
}
if (P->is_permanent_member()) {
VLOG(OVERLAY_DEBUG) << this << ": not deleting peer " << id << ": a permanent member";
return;
}
VLOG(OVERLAY_DEBUG) << this << ": deleting peer " << id; VLOG(OVERLAY_DEBUG) << this << ": deleting peer " << id;
if (P->is_neighbour()) { if (P->is_neighbour()) {
VLOG(OVERLAY_INFO) << this << ": deleting neighbour " << id; del_from_neighbour_list(P);
bool deleted = false;
for (auto &n : neighbours_) {
if (n == id) {
n = neighbours_[neighbours_.size() - 1];
neighbours_.resize(neighbours_.size() - 1);
deleted = true;
break;
}
}
CHECK(deleted);
P->set_neighbour(false);
} }
peers_.remove(id); peer_list_.peers_.remove(id);
bad_peers_.erase(id); peer_list_.bad_peers_.erase(id);
update_neighbours(0); }
void OverlayImpl::del_from_neighbour_list(OverlayPeer *P) {
CHECK(P);
if (!P->is_neighbour()) {
return;
}
auto id = P->get_id();
bool deleted = false;
auto &neighbours = peer_list_.neighbours_;
for (auto &n : neighbours) {
if (n == id) {
n = neighbours[neighbours.size() - 1];
neighbours.resize(neighbours.size() - 1);
deleted = true;
break;
}
}
CHECK(deleted);
P->set_neighbour(false);
}
void OverlayImpl::del_from_neighbour_list(const adnl::AdnlNodeIdShort &id) {
auto P = peer_list_.peers_.get(id);
CHECK(P != nullptr);
return del_from_neighbour_list(P);
} }
void OverlayImpl::del_some_peers() { void OverlayImpl::del_some_peers() {
if (!public_) { if (overlay_type_ == OverlayType::FixedMemberList) {
return; return;
} }
while (peers_.size() > max_peers()) { const size_t max_iterations = 10;
size_t iteration_seqno = 0;
while (peer_list_.peers_.size() > max_peers() && iteration_seqno++ < max_iterations) {
OverlayPeer *P; OverlayPeer *P;
if (bad_peers_.empty()) { if (peer_list_.bad_peers_.empty()) {
P = get_random_peer(); P = get_random_peer();
} else { } else {
auto it = bad_peers_.upper_bound(next_bad_peer_); auto it = peer_list_.bad_peers_.upper_bound(peer_list_.next_bad_peer_);
if (it == bad_peers_.end()) { if (it == peer_list_.bad_peers_.end()) {
it = bad_peers_.begin(); it = peer_list_.bad_peers_.begin();
} }
P = peers_.get(next_bad_peer_ = *it); P = peer_list_.peers_.get(peer_list_.next_bad_peer_ = *it);
} }
if (P) { if (P && !P->is_permanent_member()) {
auto id = P->get_id(); auto id = P->get_id();
del_peer(id); del_peer(id);
} }
} }
update_neighbours(0);
} }
void OverlayImpl::do_add_peer(OverlayNode node) { td::Status OverlayImpl::validate_peer_certificate(const adnl::AdnlNodeIdShort &node,
auto id = node.adnl_id_short(); const OverlayMemberCertificate &cert) {
if (cert.empty()) {
auto V = peers_.get(id); if (is_persistent_node(node) || overlay_type_ == OverlayType::Public) {
if (V) { return td::Status::OK();
VLOG(OVERLAY_DEBUG) << this << ": updating peer " << id << " up to version " << node.version(); }
V->update(std::move(node)); return td::Status::Error(ErrorCode::protoviolation, "no member certificate found");
} else {
VLOG(OVERLAY_DEBUG) << this << ": adding peer " << id << " of version " << node.version();
peers_.insert(id, OverlayPeer(std::move(node)));
del_some_peers();
update_neighbours(0);
} }
if (cert.is_expired()) {
return td::Status::Error(ErrorCode::timeout, "member certificate is expired");
}
if (cert.slot() < 0 || cert.slot() >= opts_.max_slaves_in_semiprivate_overlay_) {
return td::Status::Error(ErrorCode::timeout, "member certificate has invalid slot");
}
const auto &issued_by = cert.issued_by();
auto it = peer_list_.root_public_keys_.find(issued_by.compute_short_id());
if (it == peer_list_.root_public_keys_.end()) {
return td::Status::Error(ErrorCode::protoviolation, "member certificate is signed by unknown public key");
}
if (it->second.size() > (size_t)cert.slot()) {
auto &el = it->second[cert.slot()];
if (cert.expire_at() < el.expire_at) {
return td::Status::Error(ErrorCode::protoviolation,
"member certificate rejected, because we know of newer certificate at the same slot");
} else if (cert.expire_at() == el.expire_at) {
if (node < el.node) {
return td::Status::Error(ErrorCode::protoviolation,
"member certificate rejected, because we know of newer certificate at the same slot");
} else if (el.node == node) {
// we could return OK here, but we must make sure, that the unchecked signature will not be used for updating PeerNode.
}
}
}
auto R = get_encryptor(issued_by);
if (R.is_error()) {
return R.move_as_error_prefix("failed to check member certificate: failed to create encryptor: ");
}
auto enc = R.move_as_ok();
auto S = enc->check_signature(cert.to_sign_data(node).as_slice(), cert.signature());
if (S.is_error()) {
return S.move_as_error_prefix("failed to check member certificate: bad signature: ");
}
if (it->second.size() <= (size_t)cert.slot()) {
it->second.resize((size_t)cert.slot() + 1);
}
it->second[cert.slot()].expire_at = cert.expire_at();
it->second[cert.slot()].node = node;
return td::Status::OK();
} }
void OverlayImpl::add_peer_in_cont(OverlayNode node) { td::Status OverlayImpl::validate_peer_certificate(const adnl::AdnlNodeIdShort &node,
CHECK(public_); ton_api::overlay_MemberCertificate *cert) {
OverlayMemberCertificate ncert(cert);
do_add_peer(std::move(node)); return validate_peer_certificate(node, ncert);
} }
void OverlayImpl::add_peer_in(OverlayNode node) { td::Status OverlayImpl::validate_peer_certificate(const adnl::AdnlNodeIdShort &node,
CHECK(public_); const OverlayMemberCertificate *cert) {
if (!cert) {
if (is_persistent_node(node) || overlay_type_ == OverlayType::Public) {
return td::Status::OK();
}
return td::Status::Error(ErrorCode::protoviolation, "no member certificate found");
}
return validate_peer_certificate(node, *cert);
}
void OverlayImpl::add_peer(OverlayNode node) {
CHECK(overlay_type_ != OverlayType::FixedMemberList);
if (node.overlay_id() != overlay_id_) { if (node.overlay_id() != overlay_id_) {
VLOG(OVERLAY_WARNING) << this << ": received node with bad overlay"; VLOG(OVERLAY_WARNING) << this << ": received node with bad overlay";
return; return;
} }
auto t = td::Clocks::system(); auto t = td::Clocks::system();
if (node.version() + 600 < t || node.version() > t + 60) { if (node.version() + Overlays::overlay_peer_ttl() < t || node.version() > t + 60) {
VLOG(OVERLAY_INFO) << this << ": ignoring node of too old version " << node.version(); VLOG(OVERLAY_INFO) << this << ": ignoring node of too old version " << node.version();
return; return;
} }
@ -115,35 +191,80 @@ void OverlayImpl::add_peer_in(OverlayNode node) {
return; return;
} }
add_peer_in_cont(std::move(node)); if (overlay_type_ == OverlayType::CertificatedMembers) {
auto R = validate_peer_certificate(node.adnl_id_short(), *node.certificate());
if (R.is_error()) {
VLOG(OVERLAY_WARNING) << this << ": bad peer certificate node=" << node.adnl_id_short() << ": "
<< R.move_as_error();
UNREACHABLE();
return;
}
}
auto id = node.adnl_id_short();
auto V = peer_list_.peers_.get(id);
if (V) {
VLOG(OVERLAY_DEBUG) << this << ": updating peer " << id << " up to version " << node.version();
V->update(std::move(node));
} else {
VLOG(OVERLAY_DEBUG) << this << ": adding peer " << id << " of version " << node.version();
CHECK(overlay_type_ != OverlayType::CertificatedMembers || (node.certificate() && !node.certificate()->empty()));
peer_list_.peers_.insert(id, OverlayPeer(std::move(node)));
del_some_peers();
auto X = peer_list_.peers_.get(id);
CHECK(X);
if (peer_list_.neighbours_.size() < max_neighbours() &&
!(X->get_node()->flags() & OverlayMemberFlags::DoNotReceiveBroadcasts) && X->get_id() != local_id_) {
peer_list_.neighbours_.push_back(X->get_id());
X->set_neighbour(true);
}
update_neighbours(0);
}
} }
void OverlayImpl::add_peers(std::vector<OverlayNode> peers) { void OverlayImpl::add_peers(std::vector<OverlayNode> peers) {
for (auto &node : peers) { for (auto &node : peers) {
add_peer_in(std::move(node)); add_peer(std::move(node));
} }
} }
void OverlayImpl::add_peer(OverlayNode P) { void OverlayImpl::add_peers(const tl_object_ptr<ton_api::overlay_nodes> &nodes) {
add_peer_in(std::move(P)); for (auto &n : nodes->nodes_) {
auto N = OverlayNode::create(n);
if (N.is_ok()) {
add_peer(N.move_as_ok());
}
}
}
void OverlayImpl::add_peers(const tl_object_ptr<ton_api::overlay_nodesV2> &nodes) {
for (auto &n : nodes->nodes_) {
auto N = OverlayNode::create(n);
if (N.is_ok()) {
add_peer(N.move_as_ok());
}
}
} }
void OverlayImpl::on_ping_result(adnl::AdnlNodeIdShort peer, bool success) { void OverlayImpl::on_ping_result(adnl::AdnlNodeIdShort peer, bool success) {
if (!public_) { if (overlay_type_ == OverlayType::FixedMemberList) {
return; return;
} }
if (OverlayPeer *p = peers_.get(peer)) { if (OverlayPeer *p = peer_list_.peers_.get(peer)) {
p->on_ping_result(success); p->on_ping_result(success);
if (p->is_alive()) { if (p->is_alive()) {
bad_peers_.erase(peer); peer_list_.bad_peers_.erase(peer);
} else { } else {
bad_peers_.insert(peer); peer_list_.bad_peers_.insert(peer);
} }
} }
} }
void OverlayImpl::receive_random_peers(adnl::AdnlNodeIdShort src, td::Result<td::BufferSlice> R) { void OverlayImpl::receive_random_peers(adnl::AdnlNodeIdShort src, td::Result<td::BufferSlice> R) {
CHECK(public_); CHECK(overlay_type_ != OverlayType::FixedMemberList);
on_ping_result(src, R.is_ok()); on_ping_result(src, R.is_ok());
if (R.is_error()) { if (R.is_error()) {
VLOG(OVERLAY_NOTICE) << this << ": failed getRandomPeers query: " << R.move_as_error(); VLOG(OVERLAY_NOTICE) << this << ": failed getRandomPeers query: " << R.move_as_error();
@ -156,16 +277,24 @@ void OverlayImpl::receive_random_peers(adnl::AdnlNodeIdShort src, td::Result<td:
return; return;
} }
auto res = R2.move_as_ok(); add_peers(R2.move_as_ok());
}
std::vector<OverlayNode> nodes; void OverlayImpl::receive_random_peers_v2(adnl::AdnlNodeIdShort src, td::Result<td::BufferSlice> R) {
for (auto &n : res->nodes_) { CHECK(overlay_type_ != OverlayType::FixedMemberList);
auto N = OverlayNode::create(n); on_ping_result(src, R.is_ok());
if (N.is_ok()) { if (R.is_error()) {
nodes.emplace_back(N.move_as_ok()); VLOG(OVERLAY_NOTICE) << this << ": failed getRandomPeersV2 query: " << R.move_as_error();
} return;
} }
add_peers(std::move(nodes)); auto R2 = fetch_tl_object<ton_api::overlay_nodesV2>(R.move_as_ok(), true);
if (R2.is_error()) {
VLOG(OVERLAY_WARNING) << this << ": dropping incorrect answer to overlay.getRandomPeers query from " << src << ": "
<< R2.move_as_error();
return;
}
add_peers(R2.move_as_ok());
} }
void OverlayImpl::send_random_peers_cont(adnl::AdnlNodeIdShort src, OverlayNode node, void OverlayImpl::send_random_peers_cont(adnl::AdnlNodeIdShort src, OverlayNode node,
@ -175,10 +304,13 @@ void OverlayImpl::send_random_peers_cont(adnl::AdnlNodeIdShort src, OverlayNode
vec.emplace_back(node.tl()); vec.emplace_back(node.tl());
} }
for (td::uint32 i = 0; i < nodes_to_send(); i++) { td::uint32 max_iterations = nodes_to_send() + 16;
for (td::uint32 i = 0; i < max_iterations && vec.size() < nodes_to_send(); i++) {
auto P = get_random_peer(true); auto P = get_random_peer(true);
if (P) { if (P) {
vec.emplace_back(P->get().tl()); if (P->has_full_id()) {
vec.emplace_back(P->get_node()->tl());
}
} else { } else {
break; break;
} }
@ -213,58 +345,110 @@ void OverlayImpl::send_random_peers(adnl::AdnlNodeIdShort src, td::Promise<td::B
get_self_node(std::move(P)); get_self_node(std::move(P));
} }
void OverlayImpl::send_random_peers_v2_cont(adnl::AdnlNodeIdShort src, OverlayNode node,
td::Promise<td::BufferSlice> promise) {
std::vector<tl_object_ptr<ton_api::overlay_nodeV2>> vec;
if (announce_self_) {
CHECK(is_persistent_node(node.adnl_id_short()) || !node.certificate()->empty());
vec.emplace_back(node.tl_v2());
}
td::uint32 max_iterations = nodes_to_send() + 16;
for (td::uint32 i = 0; i < max_iterations && vec.size() < nodes_to_send(); i++) {
auto P = get_random_peer(true);
if (P) {
if (P->has_full_id() && !P->is_permanent_member()) {
vec.emplace_back(P->get_node()->tl_v2());
}
} else {
break;
}
}
if (promise) {
auto Q = create_tl_object<ton_api::overlay_nodesV2>(std::move(vec));
promise.set_value(serialize_tl_object(Q, true));
} else {
auto P =
td::PromiseCreator::lambda([SelfId = actor_id(this), src, oid = print_id()](td::Result<td::BufferSlice> res) {
td::actor::send_closure(SelfId, &OverlayImpl::receive_random_peers_v2, src, std::move(res));
});
auto Q =
create_tl_object<ton_api::overlay_getRandomPeersV2>(create_tl_object<ton_api::overlay_nodesV2>(std::move(vec)));
td::actor::send_closure(manager_, &OverlayManager::send_query, src, local_id_, overlay_id_,
"overlay getRandomPeers", std::move(P),
td::Timestamp::in(5.0 + td::Random::fast(0, 50) * 0.1), serialize_tl_object(Q, true));
}
}
void OverlayImpl::send_random_peers_v2(adnl::AdnlNodeIdShort src, td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda([src, promise = std::move(promise),
SelfId = actor_id(this)](td::Result<OverlayNode> res) mutable {
if (res.is_error()) {
promise.set_error(td::Status::Error(ErrorCode::error, "cannot get self node"));
return;
}
td::actor::send_closure(SelfId, &OverlayImpl::send_random_peers_v2_cont, src, res.move_as_ok(), std::move(promise));
});
get_self_node(std::move(P));
}
void OverlayImpl::update_neighbours(td::uint32 nodes_to_change) { void OverlayImpl::update_neighbours(td::uint32 nodes_to_change) {
if (peers_.size() == 0) { if (peer_list_.peers_.size() == 0) {
return; return;
} }
td::uint32 iter = 0; td::uint32 iter = 0;
while (iter < 10 && (nodes_to_change > 0 || neighbours_.size() < max_neighbours())) { while (iter++ < 10 && (nodes_to_change > 0 || peer_list_.neighbours_.size() < max_neighbours())) {
auto X = peers_.get_random(); auto X = peer_list_.peers_.get_random();
if (!X) { if (!X) {
break; break;
} }
if (X->get_id() == local_id_) { if (X->get_id() == local_id_) {
iter++;
continue; continue;
} }
if (public_ && X->get_version() <= td::Clocks::system() - 600) { if (X->get_version() <= td::Clocks::system() - Overlays::overlay_peer_ttl()) {
if (X->is_neighbour()) { if (X->is_permanent_member()) {
bool found = false; del_from_neighbour_list(X);
for (auto &n : neighbours_) { } else {
if (n == X->get_id()) { auto id = X->get_id();
n = *neighbours_.rbegin(); del_peer(id);
found = true; }
break; continue;
} }
}
CHECK(found); if (overlay_type_ == OverlayType::CertificatedMembers && !X->is_permanent_member() &&
neighbours_.pop_back(); X->certificate()->is_expired()) {
X->set_neighbour(false); auto id = X->get_id();
del_peer(id);
continue;
}
if (X->get_node()->flags() & OverlayMemberFlags::DoNotReceiveBroadcasts) {
if (X->is_neighbour()) {
del_from_neighbour_list(X);
} }
bad_peers_.erase(X->get_id());
peers_.remove(X->get_id());
continue; continue;
} }
if (X->is_neighbour()) { if (X->is_neighbour()) {
iter++;
continue; continue;
} }
if (neighbours_.size() < max_neighbours()) { if (peer_list_.neighbours_.size() < max_neighbours()) {
VLOG(OVERLAY_INFO) << this << ": adding new neighbour " << X->get_id(); VLOG(OVERLAY_INFO) << this << ": adding new neighbour " << X->get_id();
neighbours_.push_back(X->get_id()); peer_list_.neighbours_.push_back(X->get_id());
X->set_neighbour(true); X->set_neighbour(true);
} else { } else {
CHECK(nodes_to_change > 0); CHECK(nodes_to_change > 0);
auto i = td::Random::fast(0, static_cast<td::uint32>(neighbours_.size()) - 1); auto i = td::Random::fast(0, static_cast<td::uint32>(peer_list_.neighbours_.size()) - 1);
auto Y = peers_.get(neighbours_[i]); auto Y = peer_list_.peers_.get(peer_list_.neighbours_[i]);
CHECK(Y != nullptr); CHECK(Y != nullptr);
CHECK(Y->is_neighbour()); CHECK(Y->is_neighbour());
Y->set_neighbour(false); Y->set_neighbour(false);
neighbours_[i] = X->get_id(); peer_list_.neighbours_[i] = X->get_id();
X->set_neighbour(true); X->set_neighbour(true);
nodes_to_change--; nodes_to_change--;
VLOG(OVERLAY_INFO) << this << ": changing neighbour " << Y->get_id() << " -> " << X->get_id(); VLOG(OVERLAY_INFO) << this << ": changing neighbour " << Y->get_id() << " -> " << X->get_id();
@ -274,9 +458,11 @@ void OverlayImpl::update_neighbours(td::uint32 nodes_to_change) {
OverlayPeer *OverlayImpl::get_random_peer(bool only_alive) { OverlayPeer *OverlayImpl::get_random_peer(bool only_alive) {
size_t skip_bad = 3; size_t skip_bad = 3;
while (peers_.size() > (only_alive ? bad_peers_.size() : 0)) { OverlayPeer *res = nullptr;
auto P = peers_.get_random(); while (!res && peer_list_.peers_.size() > (only_alive ? peer_list_.bad_peers_.size() : 0)) {
if (public_ && P->get_version() + 3600 < td::Clocks::system()) { auto P = peer_list_.peers_.get_random();
if (!P->is_permanent_member() &&
(P->get_version() + 3600 < td::Clocks::system() || P->certificate()->is_expired())) {
VLOG(OVERLAY_INFO) << this << ": deleting outdated peer " << P->get_id(); VLOG(OVERLAY_INFO) << this << ": deleting outdated peer " << P->get_id();
del_peer(P->get_id()); del_peer(P->get_id());
continue; continue;
@ -290,18 +476,19 @@ OverlayPeer *OverlayImpl::get_random_peer(bool only_alive) {
continue; continue;
} }
} }
return P; res = P;
} }
return nullptr; update_neighbours(0);
return res;
} }
void OverlayImpl::get_overlay_random_peers(td::uint32 max_peers, void OverlayImpl::get_overlay_random_peers(td::uint32 max_peers,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) { td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) {
std::vector<adnl::AdnlNodeIdShort> v; std::vector<adnl::AdnlNodeIdShort> v;
auto t = td::Clocks::system(); auto t = td::Clocks::system();
while (v.size() < max_peers && v.size() < peers_.size() - bad_peers_.size()) { while (v.size() < max_peers && v.size() < peer_list_.peers_.size() - peer_list_.bad_peers_.size()) {
auto P = peers_.get_random(); auto P = peer_list_.peers_.get_random();
if (public_ && P->get_version() + 3600 < t) { if (!P->is_permanent_member() && (P->get_version() + 3600 < t || P->certificate()->is_expired(t))) {
VLOG(OVERLAY_INFO) << this << ": deleting outdated peer " << P->get_id(); VLOG(OVERLAY_INFO) << this << ": deleting outdated peer " << P->get_id();
del_peer(P->get_id()); del_peer(P->get_id());
} else if (P->is_alive()) { } else if (P->is_alive()) {
@ -317,22 +504,227 @@ void OverlayImpl::get_overlay_random_peers(td::uint32 max_peers,
} }
} }
} }
update_neighbours(0);
promise.set_result(std::move(v)); promise.set_result(std::move(v));
} }
void OverlayImpl::receive_nodes_from_db(tl_object_ptr<ton_api::overlay_nodes> tl_nodes) { void OverlayImpl::receive_nodes_from_db(tl_object_ptr<ton_api::overlay_nodes> tl_nodes) {
if (public_) { if (overlay_type_ != OverlayType::FixedMemberList) {
std::vector<OverlayNode> nodes; add_peers(tl_nodes);
for (auto &n : tl_nodes->nodes_) { }
auto N = OverlayNode::create(n); }
if (N.is_ok()) {
nodes.emplace_back(N.move_as_ok()); void OverlayImpl::receive_nodes_from_db_v2(tl_object_ptr<ton_api::overlay_nodesV2> tl_nodes) {
if (overlay_type_ != OverlayType::FixedMemberList) {
add_peers(tl_nodes);
}
}
bool OverlayImpl::is_persistent_node(const adnl::AdnlNodeIdShort &id) {
auto P = peer_list_.peers_.get(id);
if (!P) {
return false;
}
return P->is_permanent_member();
}
bool OverlayImpl::is_valid_peer(const adnl::AdnlNodeIdShort &src,
const ton_api::overlay_MemberCertificate *certificate) {
if (overlay_type_ == OverlayType::Public) {
on_ping_result(src, true);
return true;
} else if (overlay_type_ == OverlayType::FixedMemberList) {
return peer_list_.peers_.get(src);
} else {
OverlayMemberCertificate cert(certificate);
if (cert.empty()) {
auto P = peer_list_.peers_.get(src);
if (P && !P->is_permanent_member()) {
auto C = P->certificate();
if (C) {
cert = *C;
}
} }
} }
add_peers(std::move(nodes));
auto S = validate_peer_certificate(src, cert);
if (S.is_error()) {
VLOG(OVERLAY_WARNING) << "adnl=" << src << ": certificate is invalid: " << S;
return false;
}
auto P = peer_list_.peers_.get(src);
if (P) {
CHECK(P->is_permanent_member() || !cert.empty());
P->update_certificate(std::move(cert));
}
return true;
} }
} }
void OverlayImpl::iterate_all_peers(std::function<void(const adnl::AdnlNodeIdShort &key, OverlayPeer &peer)> cb) {
peer_list_.peers_.iterate([&](const adnl::AdnlNodeIdShort &key, OverlayPeer &peer) { cb(key, peer); });
}
void OverlayImpl::update_peer_err_ctr(adnl::AdnlNodeIdShort peer_id, bool is_fec) {
auto src_peer = peer_list_.peers_.get(peer_id);
if (src_peer) {
if (is_fec) {
src_peer->fec_broadcast_errors++;
} else {
src_peer->broadcast_errors++;
}
}
}
void OverlayImpl::update_throughput_out_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) {
auto out_peer = peer_list_.peers_.get(peer_id);
if (out_peer) {
out_peer->throughput_out_bytes_ctr += msg_size;
out_peer->throughput_out_packets_ctr++;
if (is_query) {
out_peer->last_out_query_at = td::Timestamp::now();
}
}
}
void OverlayImpl::update_throughput_in_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) {
auto in_peer = peer_list_.peers_.get(peer_id);
if (in_peer) {
in_peer->throughput_in_bytes_ctr += msg_size;
in_peer->throughput_in_packets_ctr++;
if (is_query) {
in_peer->last_in_query_at = td::Timestamp::now();
}
}
}
void OverlayImpl::update_peer_ip_str(adnl::AdnlNodeIdShort peer_id, td::string ip_str) {
auto fpeer = peer_list_.peers_.get(peer_id);
if (fpeer) {
fpeer->ip_addr_str = ip_str;
}
}
bool OverlayImpl::has_good_peers() const {
return peer_list_.peers_.size() > peer_list_.bad_peers_.size();
}
bool OverlayImpl::is_root_public_key(const PublicKeyHash &key) const {
return peer_list_.root_public_keys_.count(key) > 0;
}
std::vector<adnl::AdnlNodeIdShort> OverlayImpl::get_neighbours(td::uint32 max_size) const {
if (max_size == 0 || max_size >= peer_list_.neighbours_.size()) {
return peer_list_.neighbours_;
} else {
std::vector<adnl::AdnlNodeIdShort> vec;
std::vector<td::uint32> ul;
for (td::uint32 i = 0; i < max_size; i++) {
td::uint32 t = td::Random::fast(0, static_cast<td::int32>(peer_list_.neighbours_.size()) - 1 - i);
td::uint32 j;
for (j = 0; j < i && ul[j] <= t; j++) {
t++;
}
ul.emplace(ul.begin() + j, t);
vec.push_back(peer_list_.neighbours_[t]);
}
return vec;
}
}
void OverlayImpl::send_message_to_neighbours(td::BufferSlice data) {
wait_neighbours_not_empty([this, data = std::move(data)](td::Result<td::Unit> R) {
if (R.is_error()) {
return;
}
for (auto &n : peer_list_.neighbours_) {
td::actor::send_closure(manager_, &OverlayManager::send_message, n, local_id_, overlay_id_, data.clone());
}
});
}
size_t OverlayImpl::neighbours_cnt() const {
return peer_list_.neighbours_.size();
}
void OverlayImpl::update_root_member_list(std::vector<adnl::AdnlNodeIdShort> ids,
std::vector<PublicKeyHash> root_public_keys, OverlayMemberCertificate cert) {
td::uint32 expectd_size =
(td::uint32)(ids.size() + root_public_keys.size() * opts_.max_slaves_in_semiprivate_overlay_);
if (expectd_size > opts_.max_peers_) {
opts_.max_peers_ = expectd_size;
}
if (expectd_size > opts_.max_neighbours_) {
opts_.max_neighbours_ = expectd_size;
}
std::sort(ids.begin(), ids.end());
auto old_root_public_keys = std::move(peer_list_.root_public_keys_);
for (const auto &pub_key : root_public_keys) {
auto it = old_root_public_keys.find(pub_key);
if (it != old_root_public_keys.end()) {
peer_list_.root_public_keys_.emplace(it->first, std::move(it->second));
} else {
peer_list_.root_public_keys_.emplace(pub_key, PeerList::SlaveKeys{});
}
}
std::vector<adnl::AdnlNodeIdShort> to_del;
peer_list_.peers_.iterate([&](const adnl::AdnlNodeIdShort &key, OverlayPeer &peer) {
peer.set_permanent(std::binary_search(ids.begin(), ids.end(), key));
if (peer.is_permanent_member()) {
peer.clear_certificate();
} else {
auto S = validate_peer_certificate(peer.get_id(), peer.certificate());
if (S.is_error()) {
to_del.push_back(peer.get_id());
}
}
});
for (const auto &id : to_del) {
del_peer(id);
}
for (const auto &id : ids) {
if (!peer_list_.peers_.exists(id)) {
OverlayNode node(id, overlay_id_, opts_.default_permanent_members_flags_);
OverlayPeer peer(std::move(node));
peer.set_permanent(true);
CHECK(peer.is_permanent_member());
peer_list_.peers_.insert(std::move(id), std::move(peer));
}
}
update_member_certificate(std::move(cert));
update_neighbours(0);
}
void OverlayImpl::update_member_certificate(OverlayMemberCertificate cert) {
peer_list_.cert_ = std::move(cert);
if (is_persistent_node(local_id_)) {
peer_list_.local_cert_is_valid_until_ = td::Timestamp::in(86400.0 * 365 * 100); /* 100 years */
} else {
auto R = validate_peer_certificate(local_id_, &peer_list_.cert_);
if (R.is_ok()) {
peer_list_.local_cert_is_valid_until_ = td::Timestamp::at_unix(cert.expire_at());
} else {
peer_list_.local_cert_is_valid_until_ = td::Timestamp::never();
}
}
}
bool OverlayImpl::has_valid_membership_certificate() {
if (overlay_type_ != OverlayType::CertificatedMembers) {
return true;
}
if (!peer_list_.local_cert_is_valid_until_) {
return false;
}
return !peer_list_.local_cert_is_valid_until_.is_in_past();
}
} // namespace overlay } // namespace overlay
} // namespace ton } // namespace ton

View file

@ -18,6 +18,7 @@
*/ */
#include "auto/tl/ton_api.h" #include "auto/tl/ton_api.h"
#include "td/utils/Random.h" #include "td/utils/Random.h"
#include "common/delay.h"
#include "adnl/utils.hpp" #include "adnl/utils.hpp"
#include "dht/dht.h" #include "dht/dht.h"
@ -26,41 +27,61 @@
#include "auto/tl/ton_api.hpp" #include "auto/tl/ton_api.hpp"
#include "keys/encryptor.h" #include "keys/encryptor.h"
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h" #include "td/utils/StringBuilder.h"
#include "td/utils/port/signals.h"
#include <limits>
namespace ton { namespace ton {
namespace overlay { namespace overlay {
td::actor::ActorOwn<Overlay> Overlay::create(td::actor::ActorId<keyring::Keyring> keyring, const OverlayMemberCertificate OverlayNode::empty_certificate_{};
td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<OverlayManager> manager, td::actor::ActorOwn<Overlay> Overlay::create_public(td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id, td::actor::ActorId<adnl::Adnl> adnl,
OverlayIdFull overlay_id, std::unique_ptr<Overlays::Callback> callback, td::actor::ActorId<OverlayManager> manager,
OverlayPrivacyRules rules, td::string scope, OverlayOptions opts) { td::actor::ActorId<dht::Dht> dht_node,
auto R = td::actor::create_actor<OverlayImpl>("overlay", keyring, adnl, manager, dht_node, local_id, adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::move(overlay_id), true, std::vector<adnl::AdnlNodeIdShort>(), std::unique_ptr<Overlays::Callback> callback,
std::move(callback), std::move(rules), scope, opts); OverlayPrivacyRules rules, td::string scope, OverlayOptions opts) {
auto R = td::actor::create_actor<OverlayImpl>(
"overlay", keyring, adnl, manager, dht_node, local_id, std::move(overlay_id), OverlayType::Public,
std::vector<adnl::AdnlNodeIdShort>(), std::vector<PublicKeyHash>(), OverlayMemberCertificate{}, std::move(callback),
std::move(rules), std::move(scope), std::move(opts));
return td::actor::ActorOwn<Overlay>(std::move(R)); return td::actor::ActorOwn<Overlay>(std::move(R));
} }
td::actor::ActorOwn<Overlay> Overlay::create(td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorOwn<Overlay> Overlay::create_private(
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id,
td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Overlays::Callback> callback,
OverlayIdFull overlay_id, std::vector<adnl::AdnlNodeIdShort> nodes, OverlayPrivacyRules rules, std::string scope, OverlayOptions opts) {
std::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules,
std::string scope) {
auto R = td::actor::create_actor<OverlayImpl>("overlay", keyring, adnl, manager, dht_node, local_id, auto R = td::actor::create_actor<OverlayImpl>("overlay", keyring, adnl, manager, dht_node, local_id,
std::move(overlay_id), false, std::move(nodes), std::move(callback), std::move(overlay_id), OverlayType::FixedMemberList, std::move(nodes),
std::move(rules), std::move(scope)); std::vector<PublicKeyHash>(), OverlayMemberCertificate{},
std::move(callback), std::move(rules), std::move(scope));
return td::actor::ActorOwn<Overlay>(std::move(R));
}
td::actor::ActorOwn<Overlay> Overlay::create_semiprivate(
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id,
OverlayIdFull overlay_id, std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate cert, std::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules,
std::string scope, OverlayOptions opts) {
auto R = td::actor::create_actor<OverlayImpl>(
"overlay", keyring, adnl, manager, dht_node, local_id, std::move(overlay_id), OverlayType::CertificatedMembers,
std::move(nodes), std::move(root_public_keys), std::move(cert), std::move(callback), std::move(rules),
std::move(scope), std::move(opts));
return td::actor::ActorOwn<Overlay>(std::move(R)); return td::actor::ActorOwn<Overlay>(std::move(R));
} }
OverlayImpl::OverlayImpl(td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl, OverlayImpl::OverlayImpl(td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node, td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node,
adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, bool pub, adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, OverlayType overlay_type,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Overlays::Callback> callback, std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate cert, std::unique_ptr<Overlays::Callback> callback,
OverlayPrivacyRules rules, td::string scope, OverlayOptions opts) OverlayPrivacyRules rules, td::string scope, OverlayOptions opts)
: keyring_(keyring) : keyring_(keyring)
, adnl_(adnl) , adnl_(adnl)
@ -69,37 +90,28 @@ OverlayImpl::OverlayImpl(td::actor::ActorId<keyring::Keyring> keyring, td::actor
, local_id_(local_id) , local_id_(local_id)
, id_full_(std::move(overlay_id)) , id_full_(std::move(overlay_id))
, callback_(std::move(callback)) , callback_(std::move(callback))
, public_(pub) , overlay_type_(overlay_type)
, rules_(std::move(rules)) , rules_(std::move(rules))
, scope_(scope) , scope_(scope)
, announce_self_(opts.announce_self_) , announce_self_(opts.announce_self_)
, frequent_dht_lookup_(opts.frequent_dht_lookup_) { , opts_(std::move(opts)) {
overlay_id_ = id_full_.compute_short_id(); overlay_id_ = id_full_.compute_short_id();
frequent_dht_lookup_ = opts_.frequent_dht_lookup_;
peer_list_.local_member_flags_ = opts_.local_overlay_member_flags_;
VLOG(OVERLAY_INFO) << this << ": creating " << (public_ ? "public" : "private"); VLOG(OVERLAY_INFO) << this << ": creating";
for (auto &node : nodes) { update_root_member_list(std::move(nodes), std::move(root_public_keys), std::move(cert));
CHECK(!public_);
auto X = OverlayNode{node, overlay_id_};
do_add_peer(std::move(X));
}
update_neighbours(static_cast<td::uint32>(nodes.size())); update_neighbours(static_cast<td::uint32>(nodes.size()));
} }
void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getRandomPeers &query, void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getRandomPeers &query,
td::Promise<td::BufferSlice> promise) { td::Promise<td::BufferSlice> promise) {
if (public_) { if (overlay_type_ != OverlayType::FixedMemberList) {
VLOG(OVERLAY_DEBUG) << this << ": received " << query.peers_->nodes_.size() << " nodes from " << src VLOG(OVERLAY_DEBUG) << this << ": received " << query.peers_->nodes_.size() << " nodes from " << src
<< " in getRandomPeers query"; << " in getRandomPeers query";
std::vector<OverlayNode> nodes; add_peers(query.peers_);
for (auto &n : query.peers_->nodes_) {
auto N = OverlayNode::create(n);
if (N.is_ok()) {
nodes.emplace_back(N.move_as_ok());
}
}
add_peers(std::move(nodes));
send_random_peers(src, std::move(promise)); send_random_peers(src, std::move(promise));
} else { } else {
VLOG(OVERLAY_WARNING) << this << ": DROPPING getRandomPeers query from " << src << " in private overlay"; VLOG(OVERLAY_WARNING) << this << ": DROPPING getRandomPeers query from " << src << " in private overlay";
@ -107,6 +119,19 @@ void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getR
} }
} }
void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getRandomPeersV2 &query,
td::Promise<td::BufferSlice> promise) {
if (overlay_type_ != OverlayType::FixedMemberList) {
VLOG(OVERLAY_DEBUG) << this << ": received " << query.peers_->nodes_.size() << " nodes from " << src
<< " in getRandomPeers query";
add_peers(query.peers_);
send_random_peers_v2(src, std::move(promise));
} else {
VLOG(OVERLAY_WARNING) << this << ": DROPPING getRandomPeers query from " << src << " in private overlay";
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "overlay is private"));
}
}
void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getBroadcast &query, void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getBroadcast &query,
td::Promise<td::BufferSlice> promise) { td::Promise<td::BufferSlice> promise) {
auto it = broadcasts_.find(query.hash_); auto it = broadcasts_.find(query.hash_);
@ -139,17 +164,14 @@ void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getB
} }
*/ */
void OverlayImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) { void OverlayImpl::receive_query(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
if (!public_) { td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
auto P = peers_.get(src); if (!is_valid_peer(src, extra ? extra->certificate_.get() : nullptr)) {
if (P == nullptr) { VLOG(OVERLAY_WARNING) << this << ": received query in private overlay from unknown source " << src;
VLOG(OVERLAY_WARNING) << this << ": received query in private overlay from unknown source " << src; promise.set_error(td::Status::Error(ErrorCode::protoviolation, "overlay is not public"));
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "overlay is private")); return;
return;
}
} else {
on_ping_result(src, true);
} }
auto R = fetch_tl_object<ton_api::Function>(data.clone(), true); auto R = fetch_tl_object<ton_api::Function>(data.clone(), true);
if (R.is_error()) { if (R.is_error()) {
@ -167,16 +189,25 @@ void OverlayImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data,
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from, td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcast> bcast) { tl_object_ptr<ton_api::overlay_broadcast> bcast) {
if (peer_list_.local_member_flags_ & OverlayMemberFlags::DoNotReceiveBroadcasts) {
return td::Status::OK();
}
return BroadcastSimple::create(this, message_from, std::move(bcast)); return BroadcastSimple::create(this, message_from, std::move(bcast));
} }
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from, td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcastFec> b) { tl_object_ptr<ton_api::overlay_broadcastFec> b) {
if (peer_list_.local_member_flags_ & OverlayMemberFlags::DoNotReceiveBroadcasts) {
return td::Status::OK();
}
return OverlayFecBroadcastPart::create(this, message_from, std::move(b)); return OverlayFecBroadcastPart::create(this, message_from, std::move(b));
} }
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from, td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcastFecShort> b) { tl_object_ptr<ton_api::overlay_broadcastFecShort> b) {
if (peer_list_.local_member_flags_ & OverlayMemberFlags::DoNotReceiveBroadcasts) {
return td::Status::OK();
}
return OverlayFecBroadcastPart::create(this, message_from, std::move(b)); return OverlayFecBroadcastPart::create(this, message_from, std::move(b));
} }
@ -188,6 +219,7 @@ td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from, td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_fec_received> msg) { tl_object_ptr<ton_api::overlay_fec_received> msg) {
return td::Status::OK(); // disable this logic for now
auto it = fec_broadcasts_.find(msg->hash_); auto it = fec_broadcasts_.find(msg->hash_);
if (it != fec_broadcasts_.end()) { if (it != fec_broadcasts_.end()) {
VLOG(OVERLAY_DEBUG) << this << ": received fec opt-out message from " << message_from << " for broadcast " VLOG(OVERLAY_DEBUG) << this << ": received fec opt-out message from " << message_from << " for broadcast "
@ -202,6 +234,7 @@ td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from, td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_fec_completed> msg) { tl_object_ptr<ton_api::overlay_fec_completed> msg) {
return td::Status::OK(); // disable this logic for now
auto it = fec_broadcasts_.find(msg->hash_); auto it = fec_broadcasts_.find(msg->hash_);
if (it != fec_broadcasts_.end()) { if (it != fec_broadcasts_.end()) {
VLOG(OVERLAY_DEBUG) << this << ": received fec completed message from " << message_from << " for broadcast " VLOG(OVERLAY_DEBUG) << this << ": received fec completed message from " << message_from << " for broadcast "
@ -221,15 +254,13 @@ td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
return td::Status::OK(); return td::Status::OK();
} }
void OverlayImpl::receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data) { void OverlayImpl::receive_message(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
if (!public_) { td::BufferSlice data) {
if (peers_.get(src) == nullptr) { if (!is_valid_peer(src, extra ? extra->certificate_.get() : nullptr)) {
VLOG(OVERLAY_WARNING) << this << ": received query in private overlay from unknown source " << src; VLOG(OVERLAY_WARNING) << this << ": received message in private overlay from unknown source " << src;
return; return;
}
} else {
on_ping_result(src, true);
} }
auto X = fetch_tl_object<ton_api::overlay_Broadcast>(data.clone(), true); auto X = fetch_tl_object<ton_api::overlay_Broadcast>(data.clone(), true);
if (X.is_error()) { if (X.is_error()) {
VLOG(OVERLAY_DEBUG) << this << ": received custom message"; VLOG(OVERLAY_DEBUG) << this << ": received custom message";
@ -244,44 +275,51 @@ void OverlayImpl::receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice dat
void OverlayImpl::alarm() { void OverlayImpl::alarm() {
bcast_gc(); bcast_gc();
if(update_throughput_at_.is_in_past()) { if (update_throughput_at_.is_in_past()) {
double t_elapsed = td::Time::now() - last_throughput_update_.at(); double t_elapsed = td::Time::now() - last_throughput_update_.at();
auto SelfId = actor_id(this); auto SelfId = actor_id(this);
peers_.iterate([&](const adnl::AdnlNodeIdShort &key, OverlayPeer &peer) { iterate_all_peers([&](const adnl::AdnlNodeIdShort &key, OverlayPeer &peer) {
peer.throughput_out_bytes = static_cast<td::uint32>(peer.throughput_out_bytes_ctr / t_elapsed); peer.throughput_out_bytes = static_cast<td::uint32>(peer.throughput_out_bytes_ctr / t_elapsed);
peer.throughput_in_bytes = static_cast<td::uint32>(peer.throughput_in_bytes_ctr / t_elapsed); peer.throughput_in_bytes = static_cast<td::uint32>(peer.throughput_in_bytes_ctr / t_elapsed);
peer.throughput_out_packets = static_cast<td::uint32>(peer.throughput_out_packets_ctr / t_elapsed); peer.throughput_out_packets = static_cast<td::uint32>(peer.throughput_out_packets_ctr / t_elapsed);
peer.throughput_in_packets = static_cast<td::uint32>(peer.throughput_in_packets_ctr / t_elapsed); peer.throughput_in_packets = static_cast<td::uint32>(peer.throughput_in_packets_ctr / t_elapsed);
peer.throughput_out_bytes_ctr = 0; peer.throughput_out_bytes_ctr = 0;
peer.throughput_in_bytes_ctr = 0; peer.throughput_in_bytes_ctr = 0;
peer.throughput_out_packets_ctr = 0; peer.throughput_out_packets_ctr = 0;
peer.throughput_in_packets_ctr = 0; peer.throughput_in_packets_ctr = 0;
auto P = td::PromiseCreator::lambda([SelfId, peer_id = key](td::Result<td::string> result) { auto P = td::PromiseCreator::lambda([SelfId, peer_id = key](td::Result<td::string> result) {
result.ensure(); result.ensure();
td::actor::send_closure(SelfId, &Overlay::update_peer_ip_str, peer_id, result.move_as_ok()); td::actor::send_closure(SelfId, &Overlay::update_peer_ip_str, peer_id, result.move_as_ok());
}); });
td::actor::send_closure(adnl_, &adnl::AdnlSenderInterface::get_conn_ip_str, local_id_, key, std::move(P)); td::actor::send_closure(adnl_, &adnl::AdnlSenderInterface::get_conn_ip_str, local_id_, key, std::move(P));
}); });
update_throughput_at_ = td::Timestamp::in(50.0); update_throughput_at_ = td::Timestamp::in(50.0);
last_throughput_update_ = td::Timestamp::now(); last_throughput_update_ = td::Timestamp::now();
} }
if (public_) { if (overlay_type_ != OverlayType::FixedMemberList) {
if (peers_.size() > 0) { if (has_valid_membership_certificate()) {
auto P = get_random_peer(); auto P = get_random_peer();
if (P) { if (P) {
send_random_peers(P->get_id(), {}); if (overlay_type_ == OverlayType::Public) {
send_random_peers(P->get_id(), {});
} else {
send_random_peers_v2(P->get_id(), {});
}
} }
} else {
VLOG(OVERLAY_WARNING) << "meber certificate ist invalid, valid_until="
<< peer_list_.local_cert_is_valid_until_.at_unix();
} }
if (next_dht_query_ && next_dht_query_.is_in_past()) { if (next_dht_query_ && next_dht_query_.is_in_past() && overlay_type_ == OverlayType::Public) {
next_dht_query_ = td::Timestamp::never(); next_dht_query_ = td::Timestamp::never();
std::function<void(dht::DhtValue)> callback = [SelfId = actor_id(this)](dht::DhtValue value) { std::function<void(dht::DhtValue)> callback = [SelfId = actor_id(this)](dht::DhtValue value) {
td::actor::send_closure(SelfId, &OverlayImpl::receive_dht_nodes, std::move(value)); td::actor::send_closure(SelfId, &OverlayImpl::receive_dht_nodes, std::move(value));
@ -292,21 +330,22 @@ void OverlayImpl::alarm() {
td::actor::send_closure(dht_node_, &dht::Dht::get_value_many, dht::DhtKey{overlay_id_.pubkey_hash(), "nodes", 0}, td::actor::send_closure(dht_node_, &dht::Dht::get_value_many, dht::DhtKey{overlay_id_.pubkey_hash(), "nodes", 0},
std::move(callback), std::move(on_finish)); std::move(callback), std::move(on_finish));
} }
if (update_db_at_.is_in_past()) { if (update_db_at_.is_in_past() && overlay_type_ == OverlayType::Public) {
if (peers_.size() > 0) { std::vector<OverlayNode> vec;
std::vector<OverlayNode> vec; for (td::uint32 i = 0; i < 20; i++) {
for (td::uint32 i = 0; i < 20; i++) { auto P = get_random_peer();
auto P = get_random_peer(); if (!P) {
if (!P) { break;
break;
}
vec.push_back(P->get());
} }
vec.push_back(P->get_node()->clone());
}
if (vec.size() > 0) {
td::actor::send_closure(manager_, &OverlayManager::save_to_db, local_id_, overlay_id_, std::move(vec)); td::actor::send_closure(manager_, &OverlayManager::save_to_db, local_id_, overlay_id_, std::move(vec));
} }
update_db_at_ = td::Timestamp::in(60.0); update_db_at_ = td::Timestamp::in(60.0);
} }
update_neighbours(0);
alarm_timestamp() = td::Timestamp::in(1.0); alarm_timestamp() = td::Timestamp::in(1.0);
} else { } else {
update_neighbours(0); update_neighbours(0);
@ -315,7 +354,7 @@ void OverlayImpl::alarm() {
} }
void OverlayImpl::receive_dht_nodes(dht::DhtValue v) { void OverlayImpl::receive_dht_nodes(dht::DhtValue v) {
CHECK(public_); CHECK(overlay_type_ == OverlayType::Public);
auto R = fetch_tl_object<ton_api::overlay_nodes>(v.value().clone(), true); auto R = fetch_tl_object<ton_api::overlay_nodes>(v.value().clone(), true);
if (R.is_ok()) { if (R.is_ok()) {
auto r = R.move_as_ok(); auto r = R.move_as_ok();
@ -361,7 +400,7 @@ void OverlayImpl::dht_lookup_finished(td::Status S) {
} }
void OverlayImpl::update_dht_nodes(OverlayNode node) { void OverlayImpl::update_dht_nodes(OverlayNode node) {
if (!public_) { if (overlay_type_ != OverlayType::Public) {
return; return;
} }
@ -418,21 +457,57 @@ void OverlayImpl::bcast_gc() {
CHECK(delivered_broadcasts_.size() == bcast_lru_.size()); CHECK(delivered_broadcasts_.size() == bcast_lru_.size());
} }
void OverlayImpl::send_message_to_neighbours(td::BufferSlice data) { void OverlayImpl::wait_neighbours_not_empty(td::Promise<td::Unit> promise, int max_retries) {
for (auto &n : neighbours_) { if (!peer_list_.neighbours_.empty()) {
td::actor::send_closure(manager_, &OverlayManager::send_message, n, local_id_, overlay_id_, data.clone()); promise.set_result(td::Unit());
} else if (max_retries > 0) {
delay_action(
[SelfId = actor_id(this), promise = std::move(promise), max_retries]() mutable {
td::actor::send_closure(SelfId, &OverlayImpl::wait_neighbours_not_empty, std::move(promise), max_retries - 1);
},
td::Timestamp::in(0.5));
} else {
promise.set_error(td::Status::Error(ErrorCode::timeout));
} }
} }
void OverlayImpl::send_broadcast(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) { void OverlayImpl::send_broadcast(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) {
auto S = BroadcastSimple::create_new(actor_id(this), keyring_, send_as, std::move(data), flags); if (!has_valid_membership_certificate()) {
if (S.is_error()) { VLOG(OVERLAY_WARNING) << "member certificate is invalid, valid_until="
LOG(WARNING) << "failed to send broadcast: " << S; << peer_list_.local_cert_is_valid_until_.at_unix();
return;
} }
if (!has_valid_broadcast_certificate(send_as, data.size(), false)) {
VLOG(OVERLAY_WARNING) << "broadcast source certificate is invalid";
return;
}
wait_neighbours_not_empty([this, send_as, flags, data = std::move(data)](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
return;
}
auto S = BroadcastSimple::create_new(actor_id(this), keyring_, send_as, std::move(data), flags);
if (S.is_error()) {
LOG(WARNING) << "failed to send broadcast: " << S;
}
});
} }
void OverlayImpl::send_broadcast_fec(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) { void OverlayImpl::send_broadcast_fec(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) {
OverlayOutboundFecBroadcast::create(std::move(data), flags, actor_id(this), send_as); if (!has_valid_membership_certificate()) {
VLOG(OVERLAY_WARNING) << "meber certificate ist invalid, valid_until="
<< peer_list_.local_cert_is_valid_until_.at_unix();
return;
}
if (!has_valid_broadcast_certificate(send_as, data.size(), true)) {
VLOG(OVERLAY_WARNING) << "broadcast source certificate is invalid";
return;
}
wait_neighbours_not_empty([this, send_as, flags, data = std::move(data)](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
return;
}
OverlayOutboundFecBroadcast::create(std::move(data), flags, actor_id(this), send_as);
});
} }
void OverlayImpl::print(td::StringBuilder &sb) { void OverlayImpl::print(td::StringBuilder &sb) {
@ -450,6 +525,22 @@ td::Status OverlayImpl::check_date(td::uint32 date) {
return td::Status::OK(); return td::Status::OK();
} }
BroadcastCheckResult OverlayImpl::check_source_eligible(const PublicKeyHash &source, const Certificate *cert,
td::uint32 size, bool is_fec) {
if (size == 0) {
return BroadcastCheckResult::Forbidden;
}
auto r = rules_.check_rules(source, size, is_fec);
if (!cert || r == BroadcastCheckResult::Allowed) {
return r;
}
auto r2 = cert->check(source, overlay_id_, static_cast<td::int32>(td::Clocks::system()), size, is_fec);
r2 = broadcast_check_result_min(r2, rules_.check_rules(cert->issuer_hash(), size, is_fec));
return broadcast_check_result_max(r, r2);
}
BroadcastCheckResult OverlayImpl::check_source_eligible(PublicKey source, const Certificate *cert, td::uint32 size, BroadcastCheckResult OverlayImpl::check_source_eligible(PublicKey source, const Certificate *cert, td::uint32 size,
bool is_fec) { bool is_fec) {
if (size == 0) { if (size == 0) {
@ -457,7 +548,7 @@ BroadcastCheckResult OverlayImpl::check_source_eligible(PublicKey source, const
} }
auto short_id = source.compute_short_id(); auto short_id = source.compute_short_id();
auto r = rules_.check_rules(source.compute_short_id(), size, is_fec); auto r = rules_.check_rules(short_id, size, is_fec);
if (!cert || r == BroadcastCheckResult::Allowed) { if (!cert || r == BroadcastCheckResult::Allowed) {
return r; return r;
} }
@ -492,21 +583,23 @@ void OverlayImpl::register_fec_broadcast(std::unique_ptr<BroadcastFec> bcast) {
} }
void OverlayImpl::get_self_node(td::Promise<OverlayNode> promise) { void OverlayImpl::get_self_node(td::Promise<OverlayNode> promise) {
OverlayNode s{local_id_, overlay_id_}; OverlayNode s{local_id_, overlay_id_, peer_list_.local_member_flags_};
auto to_sign = s.to_sign(); auto to_sign = s.to_sign();
auto P = td::PromiseCreator::lambda([oid = print_id(), s = std::move(s), promise = std::move(promise)]( auto P = td::PromiseCreator::lambda(
td::Result<std::pair<td::BufferSlice, PublicKey>> R) mutable { [oid = print_id(), s = std::move(s), cert = peer_list_.cert_,
if (R.is_error()) { promise = std::move(promise)](td::Result<std::pair<td::BufferSlice, PublicKey>> R) mutable {
auto S = R.move_as_error(); if (R.is_error()) {
LOG(ERROR) << oid << ": failed to get self node: " << S; auto S = R.move_as_error();
promise.set_error(std::move(S)); LOG(ERROR) << oid << ": failed to get self node: " << S;
return; promise.set_error(std::move(S));
} return;
auto V = R.move_as_ok(); }
s.update_signature(std::move(V.first)); auto V = R.move_as_ok();
s.update_adnl_id(adnl::AdnlNodeIdFull{V.second}); s.update_signature(std::move(V.first));
promise.set_value(std::move(s)); s.update_adnl_id(adnl::AdnlNodeIdFull{V.second});
}); s.update_certificate(std::move(cert));
promise.set_value(std::move(s));
});
td::actor::send_closure(keyring_, &keyring::Keyring::sign_add_get_public_key, local_id_.pubkey_hash(), td::actor::send_closure(keyring_, &keyring::Keyring::sign_add_get_public_key, local_id_.pubkey_hash(),
std::move(to_sign), std::move(P)); std::move(to_sign), std::move(P));
@ -598,17 +691,6 @@ void OverlayImpl::check_broadcast(PublicKeyHash src, td::BufferSlice data, td::P
callback_->check_broadcast(src, overlay_id_, std::move(data), std::move(promise)); callback_->check_broadcast(src, overlay_id_, std::move(data), std::move(promise));
} }
void OverlayImpl::update_peer_err_ctr(adnl::AdnlNodeIdShort peer_id, bool is_fec) {
auto src_peer = peers_.get(peer_id);
if(src_peer) {
if(is_fec) {
src_peer->fec_broadcast_errors++;
} else {
src_peer->broadcast_errors++;
}
}
}
void OverlayImpl::broadcast_checked(Overlay::BroadcastHash hash, td::Result<td::Unit> R) { void OverlayImpl::broadcast_checked(Overlay::BroadcastHash hash, td::Result<td::Unit> R) {
{ {
auto it = broadcasts_.find(hash); auto it = broadcasts_.find(hash);
@ -630,30 +712,47 @@ void OverlayImpl::get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_
res->overlay_id_ = overlay_id_.bits256_value(); res->overlay_id_ = overlay_id_.bits256_value();
res->overlay_id_full_ = id_full_.pubkey().tl(); res->overlay_id_full_ = id_full_.pubkey().tl();
res->scope_ = scope_; res->scope_ = scope_;
peers_.iterate([&](const adnl::AdnlNodeIdShort &key, const OverlayPeer &peer) { iterate_all_peers([&](const adnl::AdnlNodeIdShort &key, const OverlayPeer &peer) {
auto node_obj = create_tl_object<ton_api::engine_validator_overlayStatsNode>(); auto node_obj = create_tl_object<ton_api::engine_validator_overlayStatsNode>();
node_obj->adnl_id_ = key.bits256_value(); node_obj->adnl_id_ = key.bits256_value();
node_obj->t_out_bytes_ = peer.throughput_out_bytes; node_obj->t_out_bytes_ = peer.throughput_out_bytes;
node_obj->t_in_bytes_ = peer.throughput_in_bytes; node_obj->t_in_bytes_ = peer.throughput_in_bytes;
node_obj->t_out_pckts_ = peer.throughput_out_packets; node_obj->t_out_pckts_ = peer.throughput_out_packets;
node_obj->t_in_pckts_ = peer.throughput_in_packets; node_obj->t_in_pckts_ = peer.throughput_in_packets;
node_obj->ip_addr_ = peer.ip_addr_str; node_obj->ip_addr_ = peer.ip_addr_str;
node_obj->last_in_query_ = static_cast<td::uint32>(peer.last_in_query_at.at_unix()); node_obj->last_in_query_ = static_cast<td::uint32>(peer.last_in_query_at.at_unix());
node_obj->last_out_query_ = static_cast<td::uint32>(peer.last_out_query_at.at_unix()); node_obj->last_out_query_ = static_cast<td::uint32>(peer.last_out_query_at.at_unix());
node_obj->bdcst_errors_ = peer.broadcast_errors; node_obj->bdcst_errors_ = peer.broadcast_errors;
node_obj->fec_bdcst_errors_ = peer.fec_broadcast_errors; node_obj->fec_bdcst_errors_ = peer.fec_broadcast_errors;
node_obj->is_neighbour_ = peer.is_neighbour();
node_obj->is_alive_ = peer.is_alive();
node_obj->node_flags_ = peer.get_node()->flags();
res->nodes_.push_back(std::move(node_obj)); res->nodes_.push_back(std::move(node_obj));
}); });
res->stats_.push_back( res->stats_.push_back(
create_tl_object<ton_api::engine_validator_oneStat>("neighbours_cnt", PSTRING() << neighbours_.size())); create_tl_object<ton_api::engine_validator_oneStat>("neighbours_cnt", PSTRING() << neighbours_cnt()));
promise.set_value(std::move(res)); callback_->get_stats_extra([promise = std::move(promise), res = std::move(res)](td::Result<std::string> R) mutable {
if (R.is_ok()) {
res->extra_ = R.move_as_ok();
}
promise.set_value(std::move(res));
});
}
bool OverlayImpl::has_valid_broadcast_certificate(const PublicKeyHash &source, size_t size, bool is_fec) {
if (size > std::numeric_limits<td::uint32>::max()) {
return false;
}
auto it = certs_.find(source);
return check_source_eligible(source, it == certs_.end() ? nullptr : it->second.get(), (td::uint32)size, is_fec);
} }
} // namespace overlay } // namespace overlay

View file

@ -18,6 +18,7 @@
*/ */
#pragma once #pragma once
#include "auto/tl/ton_api.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
#include "td/utils/int_types.h" #include "td/utils/int_types.h"
@ -37,24 +38,29 @@ class Overlay : public td::actor::Actor {
using BroadcastDataHash = td::Bits256; using BroadcastDataHash = td::Bits256;
using BroadcastPartHash = td::Bits256; using BroadcastPartHash = td::Bits256;
static td::actor::ActorOwn<Overlay> create(td::actor::ActorId<keyring::Keyring> keyring, static td::actor::ActorOwn<Overlay> create_public(
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id,
td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, std::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules,
OverlayIdFull overlay_id, std::unique_ptr<Overlays::Callback> callback, td::string scope, OverlayOptions opts = {});
OverlayPrivacyRules rules, td::string scope, OverlayOptions opts = {}); static td::actor::ActorOwn<Overlay> create_private(
static td::actor::ActorOwn<Overlay> create(td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id,
td::actor::ActorId<OverlayManager> manager, OverlayIdFull overlay_id, std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Overlays::Callback> callback,
td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id, OverlayPrivacyRules rules, std::string scope, OverlayOptions opts = {});
OverlayIdFull overlay_id, std::vector<adnl::AdnlNodeIdShort> nodes, static td::actor::ActorOwn<Overlay> create_semiprivate(
std::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
std::string scope); td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node, adnl::AdnlNodeIdShort local_id,
OverlayIdFull overlay_id, std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate cert, std::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules,
std::string scope, OverlayOptions opts = {});
virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht) = 0; virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht) = 0;
virtual void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data) = 0; virtual void receive_message(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
virtual void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0; td::BufferSlice data) = 0;
virtual void receive_query(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
virtual void send_message_to_neighbours(td::BufferSlice data) = 0; virtual void send_message_to_neighbours(td::BufferSlice data) = 0;
virtual void send_broadcast(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) = 0; virtual void send_broadcast(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) = 0;
virtual void send_broadcast_fec(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) = 0; virtual void send_broadcast_fec(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) = 0;
@ -64,12 +70,17 @@ class Overlay : public td::actor::Actor {
virtual void add_certificate(PublicKeyHash key, std::shared_ptr<Certificate>) = 0; virtual void add_certificate(PublicKeyHash key, std::shared_ptr<Certificate>) = 0;
virtual void set_privacy_rules(OverlayPrivacyRules rules) = 0; virtual void set_privacy_rules(OverlayPrivacyRules rules) = 0;
virtual void receive_nodes_from_db(tl_object_ptr<ton_api::overlay_nodes> nodes) = 0; virtual void receive_nodes_from_db(tl_object_ptr<ton_api::overlay_nodes> nodes) = 0;
virtual void receive_nodes_from_db_v2(tl_object_ptr<ton_api::overlay_nodesV2> nodes) = 0;
virtual void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_overlayStats>> promise) = 0; virtual void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_overlayStats>> promise) = 0;
virtual void update_throughput_out_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) = 0; virtual void update_throughput_out_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) = 0;
virtual void update_throughput_in_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) = 0; virtual void update_throughput_in_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) = 0;
virtual void update_peer_ip_str(adnl::AdnlNodeIdShort peer_id, td::string ip_str) = 0; virtual void update_peer_ip_str(adnl::AdnlNodeIdShort peer_id, td::string ip_str) = 0;
virtual void update_member_certificate(OverlayMemberCertificate cert) = 0;
virtual void update_root_member_list(std::vector<adnl::AdnlNodeIdShort> nodes,
std::vector<PublicKeyHash> root_public_keys, OverlayMemberCertificate cert) = 0;
//virtual void receive_broadcast(td::BufferSlice data) = 0; //virtual void receive_broadcast(td::BufferSlice data) = 0;
//virtual void subscribe(std::unique_ptr<Overlays::Callback> callback) = 0; //virtual void subscribe(std::unique_ptr<Overlays::Callback> callback) = 0;
virtual void forget_peer(adnl::AdnlNodeIdShort peer_id) = 0;
}; };
} // namespace overlay } // namespace overlay

View file

@ -18,11 +18,15 @@
*/ */
#pragma once #pragma once
#include <any>
#include <memory>
#include <vector> #include <vector>
#include <map> #include <map>
#include <set> #include <set>
#include <unordered_set>
#include <queue> #include <queue>
#include "adnl/adnl-node-id.hpp"
#include "overlay.h" #include "overlay.h"
#include "overlay-manager.h" #include "overlay-manager.h"
#include "overlay-fec.hpp" #include "overlay-fec.hpp"
@ -32,6 +36,9 @@
#include "td/utils/DecTree.h" #include "td/utils/DecTree.h"
#include "td/utils/List.h" #include "td/utils/List.h"
#include "td/utils/Status.h"
#include "td/utils/Time.h"
#include "td/utils/buffer.h"
#include "td/utils/overloaded.h" #include "td/utils/overloaded.h"
#include "fec/fec.h" #include "fec/fec.h"
@ -40,6 +47,8 @@
#include "auto/tl/ton_api.h" #include "auto/tl/ton_api.h"
#include "auto/tl/ton_api.hpp" #include "auto/tl/ton_api.hpp"
#include "td/utils/port/signals.h"
#include "tl-utils/common-utils.hpp"
namespace ton { namespace ton {
@ -58,15 +67,17 @@ class OverlayPeer {
adnl::AdnlNodeIdFull get_full_id() const { adnl::AdnlNodeIdFull get_full_id() const {
return node_.adnl_id_full(); return node_.adnl_id_full();
} }
OverlayNode get() const { const OverlayNode *get_node() const {
return node_.clone(); return &node_;
} }
void update(OverlayNode node) { void update(OverlayNode node) {
CHECK(get_id() == node.adnl_id_short()); CHECK(get_id() == node.adnl_id_short());
if (node.version() > node_.version()) { node_.update(std::move(node));
node_ = std::move(node);
}
} }
void update_certificate(OverlayMemberCertificate cert) {
node_.update_certificate(std::move(cert));
}
OverlayPeer(OverlayNode node) : node_(std::move(node)) { OverlayPeer(OverlayNode node) : node_(std::move(node)) {
id_ = node_.adnl_id_short(); id_ = node_.adnl_id_short();
} }
@ -95,24 +106,44 @@ class OverlayPeer {
return is_alive_; return is_alive_;
} }
bool is_permanent_member() const {
return is_permanent_member_;
}
void set_permanent(bool value) {
is_permanent_member_ = value;
}
void clear_certificate() {
node_.clear_certificate();
}
auto certificate() const {
return node_.certificate();
}
bool has_full_id() const {
return node_.has_full_id();
}
td::uint32 throughput_out_bytes = 0; td::uint32 throughput_out_bytes = 0;
td::uint32 throughput_in_bytes = 0; td::uint32 throughput_in_bytes = 0;
td::uint32 throughput_out_packets = 0; td::uint32 throughput_out_packets = 0;
td::uint32 throughput_in_packets = 0; td::uint32 throughput_in_packets = 0;
td::uint32 throughput_out_bytes_ctr = 0; td::uint32 throughput_out_bytes_ctr = 0;
td::uint32 throughput_in_bytes_ctr = 0; td::uint32 throughput_in_bytes_ctr = 0;
td::uint32 throughput_out_packets_ctr = 0; td::uint32 throughput_out_packets_ctr = 0;
td::uint32 throughput_in_packets_ctr = 0; td::uint32 throughput_in_packets_ctr = 0;
td::uint32 broadcast_errors = 0; td::uint32 broadcast_errors = 0;
td::uint32 fec_broadcast_errors = 0; td::uint32 fec_broadcast_errors = 0;
td::Timestamp last_in_query_at = td::Timestamp::now(); td::Timestamp last_in_query_at = td::Timestamp::now();
td::Timestamp last_out_query_at = td::Timestamp::now(); td::Timestamp last_out_query_at = td::Timestamp::now();
td::string ip_addr_str = "undefined"; td::string ip_addr_str = "undefined";
private: private:
@ -122,6 +153,7 @@ class OverlayPeer {
bool is_neighbour_ = false; bool is_neighbour_ = false;
size_t missed_pings_ = 0; size_t missed_pings_ = 0;
bool is_alive_ = true; bool is_alive_ = true;
bool is_permanent_member_ = false;
td::Timestamp last_ping_at_ = td::Timestamp::now(); td::Timestamp last_ping_at_ = td::Timestamp::now();
}; };
@ -129,19 +161,23 @@ class OverlayImpl : public Overlay {
public: public:
OverlayImpl(td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl, OverlayImpl(td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node, td::actor::ActorId<OverlayManager> manager, td::actor::ActorId<dht::Dht> dht_node,
adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, bool pub, adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, OverlayType overlay_type,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Overlays::Callback> callback, std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
OverlayPrivacyRules rules, td::string scope = "{ \"type\": \"undefined\" }", OverlayOptions opts = {}); OverlayMemberCertificate cert, std::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules,
td::string scope = "{ \"type\": \"undefined\" }", OverlayOptions opts = {});
void update_dht_node(td::actor::ActorId<dht::Dht> dht) override { void update_dht_node(td::actor::ActorId<dht::Dht> dht) override {
dht_node_ = dht; dht_node_ = dht;
} }
void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data) override; void receive_message(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override; td::BufferSlice data) override;
void receive_query(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
td::BufferSlice data, td::Promise<td::BufferSlice> promise) override;
void send_message_to_neighbours(td::BufferSlice data) override; void send_message_to_neighbours(td::BufferSlice data) override;
void send_broadcast(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) override; void send_broadcast(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) override;
void send_broadcast_fec(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) override; void send_broadcast_fec(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) override;
void receive_nodes_from_db(tl_object_ptr<ton_api::overlay_nodes> nodes) override; void receive_nodes_from_db(tl_object_ptr<ton_api::overlay_nodes> nodes) override;
void receive_nodes_from_db_v2(tl_object_ptr<ton_api::overlay_nodesV2> nodes) override;
void get_self_node(td::Promise<OverlayNode> promise); void get_self_node(td::Promise<OverlayNode> promise);
@ -149,8 +185,8 @@ class OverlayImpl : public Overlay {
void start_up() override { void start_up() override {
update_throughput_at_ = td::Timestamp::in(50.0); update_throughput_at_ = td::Timestamp::in(50.0);
last_throughput_update_ = td::Timestamp::now(); last_throughput_update_ = td::Timestamp::now();
if (public_) { if (overlay_type_ == OverlayType::Public) {
update_db_at_ = td::Timestamp::in(60.0); update_db_at_ = td::Timestamp::in(60.0);
} }
alarm_timestamp() = td::Timestamp::in(1); alarm_timestamp() = td::Timestamp::in(1);
@ -158,13 +194,17 @@ class OverlayImpl : public Overlay {
void on_ping_result(adnl::AdnlNodeIdShort peer, bool success); void on_ping_result(adnl::AdnlNodeIdShort peer, bool success);
void receive_random_peers(adnl::AdnlNodeIdShort src, td::Result<td::BufferSlice> R); void receive_random_peers(adnl::AdnlNodeIdShort src, td::Result<td::BufferSlice> R);
void receive_random_peers_v2(adnl::AdnlNodeIdShort src, td::Result<td::BufferSlice> R);
void send_random_peers(adnl::AdnlNodeIdShort dst, td::Promise<td::BufferSlice> promise); void send_random_peers(adnl::AdnlNodeIdShort dst, td::Promise<td::BufferSlice> promise);
void send_random_peers_v2(adnl::AdnlNodeIdShort dst, td::Promise<td::BufferSlice> promise);
void send_random_peers_cont(adnl::AdnlNodeIdShort dst, OverlayNode node, td::Promise<td::BufferSlice> promise); void send_random_peers_cont(adnl::AdnlNodeIdShort dst, OverlayNode node, td::Promise<td::BufferSlice> promise);
void send_random_peers_v2_cont(adnl::AdnlNodeIdShort dst, OverlayNode node, td::Promise<td::BufferSlice> promise);
void get_overlay_random_peers(td::uint32 max_peers, td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) override; void get_overlay_random_peers(td::uint32 max_peers, td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) override;
void set_privacy_rules(OverlayPrivacyRules rules) override; void set_privacy_rules(OverlayPrivacyRules rules) override;
void add_certificate(PublicKeyHash key, std::shared_ptr<Certificate> cert) override { void add_certificate(PublicKeyHash key, std::shared_ptr<Certificate> cert) override {
certs_[key] = std::move(cert); certs_[key] = std::move(cert);
} }
void update_member_certificate(OverlayMemberCertificate cert) override;
void receive_dht_nodes(dht::DhtValue v); void receive_dht_nodes(dht::DhtValue v);
void dht_lookup_finished(td::Status S); void dht_lookup_finished(td::Status S);
@ -188,6 +228,8 @@ class OverlayImpl : public Overlay {
td::Status check_date(td::uint32 date); td::Status check_date(td::uint32 date);
BroadcastCheckResult check_source_eligible(PublicKey source, const Certificate *cert, td::uint32 size, bool is_fec); BroadcastCheckResult check_source_eligible(PublicKey source, const Certificate *cert, td::uint32 size, bool is_fec);
BroadcastCheckResult check_source_eligible(const PublicKeyHash &source, const Certificate *cert, td::uint32 size,
bool is_fec);
td::Status check_delivered(BroadcastHash hash); td::Status check_delivered(BroadcastHash hash);
void broadcast_checked(Overlay::BroadcastHash hash, td::Result<td::Unit> R); void broadcast_checked(Overlay::BroadcastHash hash, td::Result<td::Unit> R);
@ -206,17 +248,7 @@ class OverlayImpl : public Overlay {
void send_new_fec_broadcast_part(PublicKeyHash local_id, Overlay::BroadcastDataHash data_hash, td::uint32 size, void send_new_fec_broadcast_part(PublicKeyHash local_id, Overlay::BroadcastDataHash data_hash, td::uint32 size,
td::uint32 flags, td::BufferSlice part, td::uint32 seqno, fec::FecType fec_type, td::uint32 flags, td::BufferSlice part, td::uint32 seqno, fec::FecType fec_type,
td::uint32 date); td::uint32 date);
std::vector<adnl::AdnlNodeIdShort> get_neighbours(td::uint32 max_size = 0) const { std::vector<adnl::AdnlNodeIdShort> get_neighbours(td::uint32 max_size = 0) const;
if (max_size == 0 || max_size >= neighbours_.size()) {
return neighbours_;
} else {
std::vector<adnl::AdnlNodeIdShort> vec;
for (td::uint32 i = 0; i < max_size; i++) {
vec.push_back(neighbours_[td::Random::fast(0, static_cast<td::int32>(neighbours_.size()) - 1)]);
}
return vec;
}
}
td::actor::ActorId<OverlayManager> overlay_manager() const { td::actor::ActorId<OverlayManager> overlay_manager() const {
return manager_; return manager_;
} }
@ -236,39 +268,59 @@ class OverlayImpl : public Overlay {
td::Result<Encryptor *> get_encryptor(PublicKey source); td::Result<Encryptor *> get_encryptor(PublicKey source);
void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_overlayStats>> promise) override; void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_overlayStats>> promise) override;
void update_throughput_out_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) override { void update_throughput_out_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) override;
auto out_peer = peers_.get(peer_id);
if(out_peer) { void update_throughput_in_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) override;
out_peer->throughput_out_bytes_ctr += msg_size;
out_peer->throughput_out_packets_ctr++; void update_peer_ip_str(adnl::AdnlNodeIdShort peer_id, td::string ip_str) override;
if(is_query) void update_root_member_list(std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
{ OverlayMemberCertificate cert) override;
out_peer->last_out_query_at = td::Timestamp::now();
} bool is_valid_peer(const adnl::AdnlNodeIdShort &id, const ton_api::overlay_MemberCertificate *certificate);
} bool is_persistent_node(const adnl::AdnlNodeIdShort &id);
td::uint32 max_data_bcasts() const {
return 100;
} }
td::uint32 max_bcasts() const {
void update_throughput_in_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) override { return 1000;
auto in_peer = peers_.get(peer_id);
if(in_peer) {
in_peer->throughput_in_bytes_ctr += msg_size;
in_peer->throughput_in_packets_ctr++;
if(is_query)
{
in_peer->last_in_query_at = td::Timestamp::now();
}
}
} }
td::uint32 max_fec_bcasts() const {
void update_peer_ip_str(adnl::AdnlNodeIdShort peer_id, td::string ip_str) override { return 20;
auto fpeer = peers_.get(peer_id);
if(fpeer) {
fpeer->ip_addr_str = ip_str;
}
} }
td::uint32 max_sources() const {
return 10;
}
td::uint32 max_encryptors() const {
return 16;
}
td::uint32 max_neighbours() const {
return opts_.max_neighbours_;
}
td::uint32 max_peers() const {
return opts_.max_peers_;
}
td::uint32 nodes_to_send() const {
return opts_.nodes_to_send_;
}
td::uint32 propagate_broadcast_to() const {
return opts_.propagate_broadcast_to_;
}
bool has_valid_membership_certificate();
bool has_valid_broadcast_certificate(const PublicKeyHash &source, size_t size, bool is_fec);
void forget_peer(adnl::AdnlNodeIdShort peer_id) override {
del_peer(peer_id);
}
void wait_neighbours_not_empty(td::Promise<td::Unit> promise, int max_retries = 20);
private: private:
template <class T> template <class T>
@ -278,6 +330,8 @@ class OverlayImpl : public Overlay {
void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getRandomPeers &query, void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getRandomPeers &query,
td::Promise<td::BufferSlice> promise); td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getRandomPeersV2 &query,
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getBroadcast &query, void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getBroadcast &query,
td::Promise<td::BufferSlice> promise); td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getBroadcastList &query, void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getBroadcastList &query,
@ -294,20 +348,28 @@ class OverlayImpl : public Overlay {
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_fec_completed> msg); td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_fec_completed> msg);
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_unicast> msg); td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_unicast> msg);
void do_add_peer(OverlayNode node); td::Status validate_peer_certificate(const adnl::AdnlNodeIdShort &node, const OverlayMemberCertificate &cert);
void add_peer_in_cont(OverlayNode node); td::Status validate_peer_certificate(const adnl::AdnlNodeIdShort &node, const OverlayMemberCertificate *cert);
void add_peer_in(OverlayNode node); td::Status validate_peer_certificate(const adnl::AdnlNodeIdShort &node, ton_api::overlay_MemberCertificate *cert);
void add_peer(OverlayNode node); void add_peer(OverlayNode node);
void add_peers(std::vector<OverlayNode> nodes); void add_peers(std::vector<OverlayNode> nodes);
void add_peers(const tl_object_ptr<ton_api::overlay_nodes> &nodes);
void add_peers(const tl_object_ptr<ton_api::overlay_nodesV2> &nodes);
void del_some_peers(); void del_some_peers();
void del_peer(adnl::AdnlNodeIdShort id); void del_peer(const adnl::AdnlNodeIdShort &id);
void del_from_neighbour_list(OverlayPeer *P);
void del_from_neighbour_list(const adnl::AdnlNodeIdShort &id);
void iterate_all_peers(std::function<void(const adnl::AdnlNodeIdShort &key, OverlayPeer &peer)> cb);
OverlayPeer *get_random_peer(bool only_alive = false); OverlayPeer *get_random_peer(bool only_alive = false);
bool is_root_public_key(const PublicKeyHash &key) const;
bool has_good_peers() const;
size_t neighbours_cnt() const;
void finish_dht_query() { void finish_dht_query() {
if (!next_dht_store_query_) { if (!next_dht_store_query_) {
next_dht_store_query_ = td::Timestamp::in(td::Random::fast(60.0, 100.0)); next_dht_store_query_ = td::Timestamp::in(td::Random::fast(60.0, 100.0));
} }
if (frequent_dht_lookup_ && peers_.size() == bad_peers_.size()) { if (frequent_dht_lookup_ && !has_good_peers()) {
next_dht_query_ = td::Timestamp::in(td::Random::fast(6.0, 10.0)); next_dht_query_ = td::Timestamp::in(td::Random::fast(6.0, 10.0));
} else { } else {
next_dht_query_ = next_dht_store_query_; next_dht_query_ = next_dht_store_query_;
@ -322,14 +384,11 @@ class OverlayImpl : public Overlay {
OverlayIdFull id_full_; OverlayIdFull id_full_;
OverlayIdShort overlay_id_; OverlayIdShort overlay_id_;
td::DecTree<adnl::AdnlNodeIdShort, OverlayPeer> peers_;
td::Timestamp next_dht_query_ = td::Timestamp::in(1.0); td::Timestamp next_dht_query_ = td::Timestamp::in(1.0);
td::Timestamp next_dht_store_query_ = td::Timestamp::in(1.0); td::Timestamp next_dht_store_query_ = td::Timestamp::in(1.0);
td::Timestamp update_db_at_; td::Timestamp update_db_at_;
td::Timestamp update_throughput_at_; td::Timestamp update_throughput_at_;
td::Timestamp last_throughput_update_; td::Timestamp last_throughput_update_;
std::set<adnl::AdnlNodeIdShort> bad_peers_;
adnl::AdnlNodeIdShort next_bad_peer_ = adnl::AdnlNodeIdShort::zero();
std::unique_ptr<Overlays::Callback> callback_; std::unique_ptr<Overlays::Callback> callback_;
@ -337,7 +396,6 @@ class OverlayImpl : public Overlay {
std::map<BroadcastHash, std::unique_ptr<BroadcastFec>> fec_broadcasts_; std::map<BroadcastHash, std::unique_ptr<BroadcastFec>> fec_broadcasts_;
std::set<BroadcastHash> delivered_broadcasts_; std::set<BroadcastHash> delivered_broadcasts_;
std::vector<adnl::AdnlNodeIdShort> neighbours_;
td::ListNode bcast_data_lru_; td::ListNode bcast_data_lru_;
td::ListNode bcast_fec_lru_; td::ListNode bcast_fec_lru_;
std::queue<BroadcastHash> bcast_lru_; std::queue<BroadcastHash> bcast_lru_;
@ -346,33 +404,6 @@ class OverlayImpl : public Overlay {
void bcast_gc(); void bcast_gc();
static td::uint32 max_data_bcasts() {
return 100;
}
static td::uint32 max_bcasts() {
return 1000;
}
static td::uint32 max_fec_bcasts() {
return 20;
}
static td::uint32 max_sources() {
return 10;
}
static td::uint32 max_neighbours() {
return 5;
}
static td::uint32 max_encryptors() {
return 16;
}
static td::uint32 max_peers() {
return 20;
}
static td::uint32 nodes_to_send() {
return 4;
}
static BroadcastHash get_broadcast_hash(adnl::AdnlNodeIdShort &src, td::Bits256 &data_hash) { static BroadcastHash get_broadcast_hash(adnl::AdnlNodeIdShort &src, td::Bits256 &data_hash) {
td::uint8 buf[64]; td::uint8 buf[64];
td::MutableSlice m{buf, 64}; td::MutableSlice m{buf, 64};
@ -382,8 +413,7 @@ class OverlayImpl : public Overlay {
return td::sha256_bits256(td::Slice(buf, 64)); return td::sha256_bits256(td::Slice(buf, 64));
} }
bool public_; OverlayType overlay_type_;
bool semi_public_ = false;
OverlayPrivacyRules rules_; OverlayPrivacyRules rules_;
td::string scope_; td::string scope_;
bool announce_self_ = true; bool announce_self_ = true;
@ -412,6 +442,25 @@ class OverlayImpl : public Overlay {
td::ListNode encryptor_lru_; td::ListNode encryptor_lru_;
std::map<PublicKeyHash, std::unique_ptr<CachedEncryptor>> encryptor_map_; std::map<PublicKeyHash, std::unique_ptr<CachedEncryptor>> encryptor_map_;
struct PeerList {
struct SlaveKey {
td::int32 expire_at{0};
adnl::AdnlNodeIdShort node{};
};
using SlaveKeys = std::vector<SlaveKey>;
std::map<PublicKeyHash, SlaveKeys> root_public_keys_;
OverlayMemberCertificate cert_;
std::set<adnl::AdnlNodeIdShort> bad_peers_;
adnl::AdnlNodeIdShort next_bad_peer_ = adnl::AdnlNodeIdShort::zero();
td::DecTree<adnl::AdnlNodeIdShort, OverlayPeer> peers_;
std::vector<adnl::AdnlNodeIdShort> neighbours_;
td::Timestamp local_cert_is_valid_until_;
td::uint32 local_member_flags_{0};
} peer_list_;
OverlayOptions opts_;
}; };
} // namespace overlay } // namespace overlay

View file

@ -18,7 +18,9 @@
*/ */
#pragma once #pragma once
#include "adnl/adnl-node-id.hpp"
#include "adnl/adnl.h" #include "adnl/adnl.h"
#include "auto/tl/ton_api.h"
#include "dht/dht.h" #include "dht/dht.h"
#include "td/actor/PromiseFuture.h" #include "td/actor/PromiseFuture.h"
@ -33,6 +35,8 @@ namespace ton {
namespace overlay { namespace overlay {
enum class OverlayType { Public, FixedMemberList, CertificatedMembers };
class OverlayIdShort { class OverlayIdShort {
public: public:
OverlayIdShort() { OverlayIdShort() {
@ -88,6 +92,10 @@ struct CertificateFlags {
enum Values : td::uint32 { AllowFec = 1, Trusted = 2 }; enum Values : td::uint32 { AllowFec = 1, Trusted = 2 };
}; };
struct OverlayMemberFlags {
enum Values : td::uint32 { DoNotReceiveBroadcasts = 1 };
};
enum BroadcastCheckResult { Forbidden = 1, NeedCheck = 2, Allowed = 3 }; enum BroadcastCheckResult { Forbidden = 1, NeedCheck = 2, Allowed = 3 };
inline BroadcastCheckResult broadcast_check_result_max(BroadcastCheckResult l, BroadcastCheckResult r) { inline BroadcastCheckResult broadcast_check_result_max(BroadcastCheckResult l, BroadcastCheckResult r) {
@ -108,7 +116,6 @@ class OverlayPrivacyRules {
} }
BroadcastCheckResult check_rules(PublicKeyHash hash, td::uint32 size, bool is_fec) { BroadcastCheckResult check_rules(PublicKeyHash hash, td::uint32 size, bool is_fec) {
auto it = authorized_keys_.find(hash); auto it = authorized_keys_.find(hash);
if (it == authorized_keys_.end()) { if (it == authorized_keys_.end()) {
if (size > max_unath_size_) { if (size > max_unath_size_) {
@ -158,9 +165,110 @@ class Certificate {
td::SharedSlice signature_; td::SharedSlice signature_;
}; };
class OverlayMemberCertificate {
public:
OverlayMemberCertificate() {
expire_at_ = std::numeric_limits<td::int32>::max();
}
OverlayMemberCertificate(PublicKey signed_by, td::uint32 flags, td::int32 slot, td::int32 expire_at,
td::BufferSlice signature)
: signed_by_(std::move(signed_by))
, flags_(flags)
, slot_(slot)
, expire_at_(expire_at)
, signature_(std::move(signature)) {
}
OverlayMemberCertificate(const OverlayMemberCertificate &other)
: signed_by_(other.signed_by_)
, flags_(other.flags_)
, slot_(other.slot_)
, expire_at_(other.expire_at_)
, signature_(other.signature_.clone()) {
}
OverlayMemberCertificate(OverlayMemberCertificate &&) = default;
OverlayMemberCertificate &operator=(OverlayMemberCertificate &&) = default;
OverlayMemberCertificate &operator=(const OverlayMemberCertificate &other) {
signed_by_ = other.signed_by_;
flags_ = other.flags_;
slot_ = other.slot_;
expire_at_ = other.expire_at_;
signature_ = other.signature_.clone();
return *this;
}
explicit OverlayMemberCertificate(const ton_api::overlay_MemberCertificate *cert);
td::Status check_signature(const adnl::AdnlNodeIdShort &node);
bool is_expired() const {
return expire_at_ < td::Clocks::system() - 3;
}
bool is_expired(double cur_time) const {
return expire_at_ < cur_time - 3;
}
tl_object_ptr<ton_api::overlay_MemberCertificate> tl() const {
if (empty()) {
return create_tl_object<ton_api::overlay_emptyMemberCertificate>();
}
return create_tl_object<ton_api::overlay_memberCertificate>(signed_by_.tl(), flags_, slot_, expire_at_,
signature_.clone_as_buffer_slice());
}
const auto &issued_by() const {
return signed_by_;
}
td::Slice signature() const {
return signature_.as_slice();
}
td::BufferSlice to_sign_data(const adnl::AdnlNodeIdShort &node) const {
return ton::create_serialize_tl_object<ton::ton_api::overlay_memberCertificateId>(node.tl(), flags_, slot_,
expire_at_);
}
bool empty() const {
return signed_by_.empty();
}
bool is_newer(const OverlayMemberCertificate &other) const {
return !empty() && expire_at_ > other.expire_at_;
}
auto slot() const {
return slot_;
}
auto expire_at() const {
return expire_at_;
}
void set_signature(td::Slice signature) {
signature_ = td::SharedSlice(signature);
}
void set_signature(td::SharedSlice signature) {
signature_ = std::move(signature);
}
private:
PublicKey signed_by_;
td::uint32 flags_;
td::int32 slot_;
td::int32 expire_at_ = std::numeric_limits<td::int32>::max();
td::SharedSlice signature_;
};
struct OverlayOptions { struct OverlayOptions {
bool announce_self_ = true; bool announce_self_ = true;
bool frequent_dht_lookup_ = false; bool frequent_dht_lookup_ = false;
td::uint32 local_overlay_member_flags_ = 0;
td::int32 max_slaves_in_semiprivate_overlay_ = 5;
td::uint32 max_peers_ = 20;
td::uint32 max_neighbours_ = 5;
td::uint32 nodes_to_send_ = 4;
td::uint32 propagate_broadcast_to_ = 5;
td::uint32 default_permanent_members_flags_ = 0;
}; };
class Overlays : public td::actor::Actor { class Overlays : public td::actor::Actor {
@ -175,6 +283,9 @@ class Overlays : public td::actor::Actor {
td::Promise<td::Unit> promise) { td::Promise<td::Unit> promise) {
promise.set_value(td::Unit()); promise.set_value(td::Unit());
} }
virtual void get_stats_extra(td::Promise<std::string> promise) {
promise.set_result("");
}
virtual ~Callback() = default; virtual ~Callback() = default;
}; };
@ -192,6 +303,10 @@ class Overlays : public td::actor::Actor {
return 1; return 1;
} }
static constexpr td::uint32 overlay_peer_ttl() {
return 600;
}
static td::actor::ActorOwn<Overlays> create(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring, static td::actor::ActorOwn<Overlays> create(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<dht::Dht> dht); td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<dht::Dht> dht);
@ -201,11 +316,20 @@ class Overlays : public td::actor::Actor {
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, std::unique_ptr<Callback> callback, OverlayPrivacyRules rules,
td::string scope) = 0; td::string scope) = 0;
virtual void create_public_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, virtual void create_public_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope,
td::string scope, OverlayOptions opts) = 0; OverlayOptions opts) = 0;
virtual void create_semiprivate_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes,
std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate certificate,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules,
td::string scope, OverlayOptions opts) = 0;
virtual void create_private_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, virtual void create_private_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback, std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback,
OverlayPrivacyRules rules, std::string scope) = 0; OverlayPrivacyRules rules, std::string scope) = 0;
virtual void create_private_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback,
OverlayPrivacyRules rules, std::string scope, OverlayOptions opts) = 0;
virtual void delete_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id) = 0; virtual void delete_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id) = 0;
virtual void send_query(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, virtual void send_query(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
@ -239,9 +363,18 @@ class Overlays : public td::actor::Actor {
virtual void update_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, PublicKeyHash key, virtual void update_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, PublicKeyHash key,
std::shared_ptr<Certificate> cert) = 0; std::shared_ptr<Certificate> cert) = 0;
virtual void update_member_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
OverlayMemberCertificate certificate) = 0;
virtual void update_root_member_list(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes,
std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate certificate) = 0;
virtual void get_overlay_random_peers(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay, td::uint32 max_peers, virtual void get_overlay_random_peers(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay, td::uint32 max_peers,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) = 0; td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) = 0;
virtual void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_overlaysStats>> promise) = 0; virtual void get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_overlaysStats>> promise) = 0;
virtual void forget_peer(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay, adnl::AdnlNodeIdShort peer_id) = 0;
}; };
} // namespace overlay } // namespace overlay

450
test/test-overlay.cpp Normal file
View file

@ -0,0 +1,450 @@
/*
This file is part of TON Blockchain source code.
TON Blockchain is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
TON Blockchain is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2020 Telegram Systems LLP
*/
#include "adnl/adnl-node-id.hpp"
#include "adnl/adnl.h"
#include "adnl/utils.hpp"
#include "adnl/adnl-test-loopback-implementation.h"
#include "auto/tl/ton_api.h"
#include "checksum.h"
#include "common/bitstring.h"
#include "dht/dht.h"
#include "keys/keys.hpp"
#include "overlay-manager.h"
#include "overlay.h"
#include "overlay-id.hpp"
#include "overlay/overlays.h"
#include "td/actor/actor.h"
#include "td/utils/OptionParser.h"
#include "td/utils/Status.h"
#include "td/utils/Time.h"
#include "td/utils/UInt.h"
#include "td/utils/buffer.h"
#include "td/utils/crypto.h"
#include "td/utils/filesystem.h"
#include "td/utils/format.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include "td/utils/port/signals.h"
#include "td/utils/port/FileFd.h"
#include "td/utils/overloaded.h"
#include "common/errorlog.h"
#include "tl-utils/common-utils.hpp"
#include "tl/TlObject.h"
#include <memory>
#include <vector>
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
#include <set>
struct Node {
ton::PrivateKey pk;
ton::PublicKeyHash id;
ton::PublicKey id_full;
ton::adnl::AdnlNodeIdShort adnl_id;
ton::adnl::AdnlNodeIdFull adnl_id_full;
bool can_receive;
};
static std::vector<Node> root_nodes;
static std::vector<Node> slave_nodes;
static std::vector<Node *> all_nodes;
static td::uint32 total_nodes = 4;
static td::int32 node_slaves_cnt = 3;
static size_t remaining = 0;
static td::Bits256 bcast_hash;
class Callback : public ton::overlay::Overlays::Callback {
public:
Callback(bool can_receive) : can_receive_(can_receive) {
}
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::overlay::OverlayIdShort overlay_id,
td::BufferSlice data) override {
UNREACHABLE();
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::overlay::OverlayIdShort overlay_id, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
UNREACHABLE();
}
void receive_broadcast(ton::PublicKeyHash src, ton::overlay::OverlayIdShort overlay_id,
td::BufferSlice data) override {
CHECK(can_receive_);
CHECK(td::sha256_bits256(data.as_slice()) == bcast_hash);
CHECK(remaining > 0);
remaining--;
}
private:
bool can_receive_;
};
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_INFO);
td::set_default_failure_signal_handler().ensure();
std::string db_root_ = "tmp-dir-test-catchain";
td::rmrf(db_root_).ignore();
td::mkdir(db_root_).ensure();
td::set_default_failure_signal_handler().ensure();
td::actor::ActorOwn<ton::keyring::Keyring> keyring;
td::actor::ActorOwn<ton::adnl::TestLoopbackNetworkManager> network_manager;
td::actor::ActorOwn<ton::adnl::Adnl> adnl;
td::actor::ActorOwn<ton::overlay::Overlays> overlay_manager;
td::actor::Scheduler scheduler({7});
scheduler.run_in_context([&] {
ton::errorlog::ErrorLog::create(db_root_);
keyring = ton::keyring::Keyring::create(db_root_);
network_manager = td::actor::create_actor<ton::adnl::TestLoopbackNetworkManager>("test net");
adnl = ton::adnl::Adnl::create(db_root_, keyring.get());
overlay_manager =
ton::overlay::Overlays::create(db_root_, keyring.get(), adnl.get(), td::actor::ActorId<ton::dht::Dht>{});
td::actor::send_closure(adnl, &ton::adnl::Adnl::register_network_manager, network_manager.get());
});
td::uint32 att = 0;
for (td::uint32 start = att; att < start + 5; att++) {
LOG(WARNING) << "Test #" << att;
root_nodes.resize(total_nodes);
slave_nodes.resize(total_nodes * node_slaves_cnt);
auto overlay_id_full =
ton::create_serialize_tl_object<ton::ton_api::pub_overlay>(td::BufferSlice(PSTRING() << "TEST" << att));
ton::overlay::OverlayIdFull overlay_id(overlay_id_full.clone());
auto overlay_id_short = overlay_id.compute_short_id();
ton::overlay::OverlayOptions opts;
opts.max_slaves_in_semiprivate_overlay_ = node_slaves_cnt;
opts.default_permanent_members_flags_ = ton::overlay::OverlayMemberFlags::DoNotReceiveBroadcasts;
ton::overlay::OverlayPrivacyRules rules(
20 << 20, ton::overlay::CertificateFlags::AllowFec | ton::overlay::CertificateFlags::Trusted, {});
std::vector<ton::PublicKeyHash> root_keys;
std::vector<ton::adnl::AdnlNodeIdShort> root_adnl;
size_t real_members = 0;
scheduler.run_in_context([&] {
auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list();
for (auto &n : root_nodes) {
bool receive_bcasts = (real_members == 0) ? true : (td::Random::fast_uint32() & 1);
if (receive_bcasts) {
real_members++;
}
n.can_receive = receive_bcasts;
auto pk1 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub1 = pk1.compute_public_key();
n.adnl_id_full = ton::adnl::AdnlNodeIdFull{pub1};
n.adnl_id = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr,
static_cast<td::uint8>(0));
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, n.adnl_id, true,
true);
auto pk2 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub2 = pk2.compute_public_key();
n.id_full = pub2;
n.id = pub2.compute_short_id();
n.pk = pk2;
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk2), true, [](td::Unit) {});
LOG(DEBUG) << "created node " << n.adnl_id << " " << n.id;
all_nodes.push_back(&n);
root_keys.push_back(n.id);
root_adnl.push_back(n.adnl_id);
}
for (auto &n : slave_nodes) {
bool receive_bcasts = (real_members == 0) ? true : (td::Random::fast_uint32() & 1);
if (receive_bcasts) {
real_members++;
}
n.can_receive = receive_bcasts;
auto pk1 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub1 = pk1.compute_public_key();
n.adnl_id_full = ton::adnl::AdnlNodeIdFull{pub1};
n.adnl_id = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr,
static_cast<td::uint8>(0));
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, n.adnl_id, true,
true);
auto pk2 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub2 = pk2.compute_public_key();
n.id_full = pub2;
n.id = pub2.compute_short_id();
n.pk = pk2;
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk2), true, [](td::Unit) {});
LOG(DEBUG) << "created node " << n.adnl_id << " " << n.id;
all_nodes.push_back(&n);
}
for (auto &n1 : all_nodes) {
for (auto &n2 : all_nodes) {
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_peer, n1->adnl_id, n2->adnl_id_full, addr);
}
}
for (auto &n1 : root_nodes) {
opts.local_overlay_member_flags_ =
(n1.can_receive ? 0 : ton::overlay::OverlayMemberFlags::DoNotReceiveBroadcasts);
td::actor::send_closure(overlay_manager, &ton::overlay::Overlays::create_semiprivate_overlay, n1.adnl_id,
ton::overlay::OverlayIdFull(overlay_id_full.clone()), root_adnl, root_keys,
ton::overlay::OverlayMemberCertificate{}, std::make_unique<Callback>(n1.can_receive),
rules, "", opts);
}
for (size_t i = 0; i < slave_nodes.size(); i++) {
auto &n1 = slave_nodes[i];
opts.local_overlay_member_flags_ =
(n1.can_receive ? 0 : ton::overlay::OverlayMemberFlags::DoNotReceiveBroadcasts);
ton::overlay::OverlayMemberCertificate cert(root_nodes[i / node_slaves_cnt].id_full, 0, i % node_slaves_cnt,
2000000000, td::BufferSlice());
auto buf = cert.to_sign_data(n1.adnl_id);
auto dec = root_nodes[i / node_slaves_cnt].pk.create_decryptor().move_as_ok();
auto signature = dec->sign(buf.as_slice()).move_as_ok();
cert.set_signature(signature.as_slice());
auto enc = root_nodes[i / node_slaves_cnt].id_full.create_encryptor().move_as_ok();
enc->check_signature(cert.to_sign_data(n1.adnl_id), cert.signature()).ensure();
td::actor::send_closure(overlay_manager, &ton::overlay::Overlays::create_semiprivate_overlay, n1.adnl_id,
ton::overlay::OverlayIdFull(overlay_id_full.clone()), root_adnl, root_keys, cert,
std::make_unique<Callback>(n1.can_receive), rules, "", opts);
}
});
td::BufferSlice broadcast(1 << 20);
td::Random::secure_bytes(broadcast.as_slice());
remaining = real_members;
bcast_hash = td::sha256_bits256(broadcast.as_slice());
auto t = td::Timestamp::in(20.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
}
scheduler.run_in_context([&] {
/*td::actor::send_closure(overlay_manager, &ton::overlay::Overlays::get_stats,
[&](td::Result<ton::tl_object_ptr<ton::ton_api::engine_validator_overlaysStats>> R) {
if (R.is_ok()) {
auto res = R.move_as_ok();
for (auto &o : res->overlays_) {
if (o->overlay_id_ == overlay_id_short.bits256_value()) {
LOG(ERROR) << "NODE " << o->adnl_id_ << " nodes=" << o->nodes_.size();
for (auto &x : o->stats_) {
LOG(ERROR) << "\t" << x->key_ << " " << x->value_;
}
for (auto &x : o->nodes_) {
LOG(ERROR) << "\t\t" << x->adnl_id_;
}
}
}
}
});*/
td::actor::send_closure(overlay_manager, &ton::overlay::Overlays::send_broadcast_fec_ex, root_nodes[0].adnl_id,
overlay_id_short, root_nodes[0].id, 0, std::move(broadcast));
});
t = td::Timestamp::in(10.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
if (!remaining) {
break;
}
}
LOG_CHECK(!remaining) << "remaining=" << remaining << " all=" << real_members;
broadcast = td::BufferSlice(700);
td::Random::secure_bytes(broadcast.as_slice());
remaining = real_members;
bcast_hash = td::sha256_bits256(broadcast.as_slice());
scheduler.run_in_context([&] {
td::actor::send_closure(overlay_manager, &ton::overlay::Overlays::send_broadcast_ex, root_nodes[0].adnl_id,
overlay_id_short, root_nodes[0].id, 0, std::move(broadcast));
});
t = td::Timestamp::in(10.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
if (!remaining) {
break;
}
}
LOG_CHECK(!remaining) << "remaining=" << remaining;
scheduler.run_in_context([&] {
root_nodes.clear();
slave_nodes.clear();
all_nodes.clear();
});
}
for (td::uint32 start = att; att < start + 5; att++) {
LOG(WARNING) << "Test #" << att;
root_nodes.resize(total_nodes);
auto overlay_id_full =
ton::create_serialize_tl_object<ton::ton_api::pub_overlay>(td::BufferSlice(PSTRING() << "TEST" << att));
ton::overlay::OverlayIdFull overlay_id(overlay_id_full.clone());
auto overlay_id_short = overlay_id.compute_short_id();
ton::overlay::OverlayOptions opts;
ton::overlay::OverlayPrivacyRules rules(
20 << 20, ton::overlay::CertificateFlags::AllowFec | ton::overlay::CertificateFlags::Trusted, {});
std::vector<ton::PublicKeyHash> root_keys;
std::vector<ton::adnl::AdnlNodeIdShort> root_adnl;
size_t real_members = 0;
scheduler.run_in_context([&] {
auto addr = ton::adnl::TestLoopbackNetworkManager::generate_dummy_addr_list();
for (auto &n : root_nodes) {
real_members++;
auto pk1 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub1 = pk1.compute_public_key();
n.adnl_id_full = ton::adnl::AdnlNodeIdFull{pub1};
n.adnl_id = ton::adnl::AdnlNodeIdShort{pub1.compute_short_id()};
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk1), true, [](td::Unit) {});
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub1}, addr,
static_cast<td::uint8>(0));
td::actor::send_closure(network_manager, &ton::adnl::TestLoopbackNetworkManager::add_node_id, n.adnl_id, true,
true);
auto pk2 = ton::PrivateKey{ton::privkeys::Ed25519::random()};
auto pub2 = pk2.compute_public_key();
n.id_full = pub2;
n.id = pub2.compute_short_id();
n.pk = pk2;
td::actor::send_closure(keyring, &ton::keyring::Keyring::add_key, std::move(pk2), true, [](td::Unit) {});
LOG(DEBUG) << "created node " << n.adnl_id << " " << n.id;
all_nodes.push_back(&n);
root_keys.push_back(n.id);
root_adnl.push_back(n.adnl_id);
}
for (auto &n1 : all_nodes) {
for (auto &n2 : all_nodes) {
td::actor::send_closure(adnl, &ton::adnl::Adnl::add_peer, n1->adnl_id, n2->adnl_id_full, addr);
}
}
for (auto &n1 : root_nodes) {
td::actor::send_closure(overlay_manager, &ton::overlay::Overlays::create_private_overlay_ex, n1.adnl_id,
ton::overlay::OverlayIdFull(overlay_id_full.clone()), root_adnl,
std::make_unique<Callback>(true), rules, "", opts);
}
});
auto t = td::Timestamp::in(10.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
}
td::BufferSlice broadcast(1 << 20);
td::Random::secure_bytes(broadcast.as_slice());
remaining = real_members;
bcast_hash = td::sha256_bits256(broadcast.as_slice());
scheduler.run_in_context([&] {
td::actor::send_closure(overlay_manager, &ton::overlay::Overlays::send_broadcast_fec_ex, root_nodes[0].adnl_id,
overlay_id_short, root_nodes[0].id, 0, std::move(broadcast));
});
t = td::Timestamp::in(10.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
if (!remaining) {
break;
}
}
LOG_CHECK(!remaining) << "remaining=" << remaining;
broadcast = td::BufferSlice(700);
td::Random::secure_bytes(broadcast.as_slice());
remaining = real_members;
bcast_hash = td::sha256_bits256(broadcast.as_slice());
scheduler.run_in_context([&] {
td::actor::send_closure(overlay_manager, &ton::overlay::Overlays::send_broadcast_ex, root_nodes[0].adnl_id,
overlay_id_short, root_nodes[0].id, 0, std::move(broadcast));
});
t = td::Timestamp::in(10.0);
while (scheduler.run(1)) {
if (t.is_in_past()) {
break;
}
if (!remaining) {
break;
}
}
LOG_CHECK(!remaining) << "remaining=" << remaining;
scheduler.run_in_context([&] {
root_nodes.clear();
slave_nodes.clear();
all_nodes.clear();
});
}
td::rmrf(db_root_).ensure();
std::_Exit(0);
return 0;
}

View file

@ -101,6 +101,10 @@ class Description : public ton::validatorsession::ValidatorSessionDescription {
td::uint32 get_max_priority() const override { td::uint32 get_max_priority() const override {
return opts_.round_candidates - 1; return opts_.round_candidates - 1;
} }
td::uint32 get_node_by_priority(td::uint32 round, td::uint32 priority) const override {
CHECK(priority <= get_max_priority());
return (round + priority) % get_total_nodes();
}
td::uint32 get_unixtime(td::uint64 ts) const override { td::uint32 get_unixtime(td::uint64 ts) const override {
return static_cast<td::uint32>(ts >> 32); return static_cast<td::uint32>(ts >> 32);
} }

View file

@ -148,6 +148,39 @@ td::Result<tl_object_ptr<std::enable_if_t<!std::is_constructible<T>::value, T>>>
} }
} }
template <typename T>
td::Result<tl_object_ptr<std::enable_if_t<std::is_constructible<T>::value, T>>> fetch_tl_prefix(td::Slice &data,
bool boxed) {
td::TlParser p(data);
tl_object_ptr<T> R;
if (boxed) {
R = TlFetchBoxed<TlFetchObject<T>, T::ID>::parse(p);
} else {
R = move_tl_object_as<T>(T::fetch(p));
}
if (p.get_status().is_ok()) {
data.remove_prefix(data.size() - p.get_left_len());
return std::move(R);
} else {
return p.get_status();
}
}
template <typename T>
td::Result<tl_object_ptr<std::enable_if_t<!std::is_constructible<T>::value, T>>> fetch_tl_prefix(td::Slice &data,
bool boxed) {
CHECK(boxed);
td::TlParser p(data);
tl_object_ptr<T> R;
R = move_tl_object_as<T>(T::fetch(p));
if (p.get_status().is_ok()) {
data.remove_prefix(data.size() - p.get_left_len());
return std::move(R);
} else {
return p.get_status();
}
}
template <class T> template <class T>
[[deprecated]] tl_object_ptr<T> clone_tl_object(const tl_object_ptr<T> &obj) { [[deprecated]] tl_object_ptr<T> clone_tl_object(const tl_object_ptr<T> &obj) {
auto B = serialize_tl_object(obj, true); auto B = serialize_tl_object(obj, true);

View file

@ -209,10 +209,15 @@ dht.query node:dht.node = True;
---types--- ---types---
overlay.node.toSign id:adnl.id.short overlay:int256 version:int = overlay.node.ToSign; overlay.node.toSign id:adnl.id.short overlay:int256 version:int = overlay.node.ToSign;
overlay.node.toSignEx id:adnl.id.short overlay:int256 flags:int version:int = overlay.node.ToSign;
overlay.node id:PublicKey overlay:int256 version:int signature:bytes = overlay.Node; overlay.node id:PublicKey overlay:int256 version:int signature:bytes = overlay.Node;
overlay.nodeV2 id:PublicKey overlay:int256 flags:int version:int signature:bytes certificate:overlay.MemberCertificate = overlay.NodeV2;
overlay.nodes nodes:(vector overlay.node) = overlay.Nodes; overlay.nodes nodes:(vector overlay.node) = overlay.Nodes;
overlay.nodesV2 nodes:(vector overlay.NodeV2) = overlay.NodesV2;
overlay.messageExtra flags:# certificate:flags.0?overlay.MemberCertificate = overlay.MessageExtra;
overlay.message overlay:int256 = overlay.Message; overlay.message overlay:int256 = overlay.Message;
overlay.messageWithExtra overlay:int256 extra:overlay.messageExtra = overlay.Message;
//overlay.randomPeers peers:(vector adnl.node) = overlay.RandomPeers; //overlay.randomPeers peers:(vector adnl.node) = overlay.RandomPeers;
overlay.broadcastList hashes:(vector int256) = overlay.BroadcastList; overlay.broadcastList hashes:(vector int256) = overlay.BroadcastList;
@ -225,6 +230,9 @@ overlay.broadcastFec.partId broadcast_hash:int256 data_hash:int256 seqno:int = o
overlay.broadcast.toSign hash:int256 date:int = overlay.broadcast.ToSign; overlay.broadcast.toSign hash:int256 date:int = overlay.broadcast.ToSign;
overlay.memberCertificateId node:adnl.id.short flags:int slot:int expire_at:int = overlay.MemberCertificateId;
overlay.memberCertificate issued_by:PublicKey flags:int slot:int expire_at:int signature:bytes = overlay.MemberCertificate;
overlay.emptyMemberCertificate = overlay.MemberCertificate;
overlay.certificate issued_by:PublicKey expire_at:int max_size:int signature:bytes = overlay.Certificate; overlay.certificate issued_by:PublicKey expire_at:int max_size:int signature:bytes = overlay.Certificate;
overlay.certificateV2 issued_by:PublicKey expire_at:int max_size:int flags:int signature:bytes = overlay.Certificate; overlay.certificateV2 issued_by:PublicKey expire_at:int max_size:int flags:int signature:bytes = overlay.Certificate;
overlay.emptyCertificate = overlay.Certificate; overlay.emptyCertificate = overlay.Certificate;
@ -242,13 +250,16 @@ overlay.broadcastNotFound = overlay.Broadcast;
---functions--- ---functions---
overlay.getRandomPeers peers:overlay.nodes = overlay.Nodes; overlay.getRandomPeers peers:overlay.nodes = overlay.Nodes;
overlay.getRandomPeersV2 peers:overlay.NodesV2 = overlay.NodesV2;
overlay.query overlay:int256 = True; overlay.query overlay:int256 = True;
overlay.queryWithExtra overlay:int256 extra:overlay.messageExtra = True;
overlay.getBroadcast hash:int256 = overlay.Broadcast; overlay.getBroadcast hash:int256 = overlay.Broadcast;
overlay.getBroadcastList list:overlay.broadcastList = overlay.BroadcastList; overlay.getBroadcastList list:overlay.broadcastList = overlay.BroadcastList;
---types--- ---types---
overlay.db.nodesV2 nodes:overlay.nodesV2 = overlay.db.Nodes;
overlay.db.nodes nodes:overlay.nodes = overlay.db.Nodes; overlay.db.nodes nodes:overlay.nodes = overlay.db.Nodes;
overlay.db.key.nodes local_id:int256 overlay:int256 = overlay.db.Key; overlay.db.key.nodes local_id:int256 overlay:int256 = overlay.db.Key;
@ -366,6 +377,7 @@ tonNode.blockSignature who:int256 signature:bytes = tonNode.BlockSignature;
tonNode.blockId workchain:int shard:long seqno:int = tonNode.BlockId; tonNode.blockId workchain:int shard:long seqno:int = tonNode.BlockId;
tonNode.blockIdExt workchain:int shard:long seqno:int root_hash:int256 file_hash:int256 = tonNode.BlockIdExt; tonNode.blockIdExt workchain:int shard:long seqno:int root_hash:int256 file_hash:int256 = tonNode.BlockIdExt;
tonNode.zeroStateIdExt workchain:int root_hash:int256 file_hash:int256 = tonNode.ZeroStateIdExt; tonNode.zeroStateIdExt workchain:int root_hash:int256 file_hash:int256 = tonNode.ZeroStateIdExt;
tonNode.shardId workchain:int shard:long = tonNode.ShardId;
tonNode.blockDescriptionEmpty = tonNode.BlockDescription; tonNode.blockDescriptionEmpty = tonNode.BlockDescription;
tonNode.blockDescription id:tonNode.blockIdExt = tonNode.BlockDescription; tonNode.blockDescription id:tonNode.blockIdExt = tonNode.BlockDescription;
@ -502,6 +514,7 @@ db.filedb.key.proof block_id:tonNode.blockIdExt = db.filedb.Key;
db.filedb.key.proofLink block_id:tonNode.blockIdExt = db.filedb.Key; db.filedb.key.proofLink block_id:tonNode.blockIdExt = db.filedb.Key;
db.filedb.key.signatures block_id:tonNode.blockIdExt = db.filedb.Key; db.filedb.key.signatures block_id:tonNode.blockIdExt = db.filedb.Key;
db.filedb.key.candidate id:db.candidate.id = db.filedb.Key; db.filedb.key.candidate id:db.candidate.id = db.filedb.Key;
db.filedb.key.candidateRef id:tonNode.blockIdExt = db.filedb.Key;
db.filedb.key.blockInfo block_id:tonNode.blockIdExt = db.filedb.Key; db.filedb.key.blockInfo block_id:tonNode.blockIdExt = db.filedb.Key;
db.filedb.value key:db.filedb.Key prev:int256 next:int256 file_hash:int256 = db.filedb.Value; db.filedb.value key:db.filedb.Key prev:int256 next:int256 file_hash:int256 = db.filedb.Value;
@ -649,9 +662,10 @@ engine.validator.proposalVote perm_key:int256 to_send:bytes = engine.validator.P
engine.validator.dhtServerStatus id:int256 status:int = engine.validator.DhtServerStatus; engine.validator.dhtServerStatus id:int256 status:int = engine.validator.DhtServerStatus;
engine.validator.dhtServersStatus servers:(vector engine.validator.dhtServerStatus) = engine.validator.DhtServersStatus; engine.validator.dhtServersStatus servers:(vector engine.validator.dhtServerStatus) = engine.validator.DhtServersStatus;
engine.validator.overlayStatsNode adnl_id:int256 ip_addr:string bdcst_errors:int fec_bdcst_errors:int last_in_query:int last_out_query:int t_out_bytes:int t_in_bytes:int t_out_pckts:int t_in_pckts:int = engine.validator.OverlayStatsNode; engine.validator.overlayStatsNode adnl_id:int256 ip_addr:string is_neighbour:Bool is_alive:Bool node_flags:int
bdcst_errors:int fec_bdcst_errors:int last_in_query:int last_out_query:int t_out_bytes:int t_in_bytes:int t_out_pckts:int t_in_pckts:int = engine.validator.OverlayStatsNode;
engine.validator.overlayStats overlay_id:int256 overlay_id_full:PublicKey adnl_id:int256 scope:string nodes:(vector engine.validator.overlayStatsNode) stats:(vector engine.validator.oneStat) = engine.validator.OverlayStats; engine.validator.overlayStats overlay_id:int256 overlay_id_full:PublicKey adnl_id:int256 scope:string nodes:(vector engine.validator.overlayStatsNode) stats:(vector engine.validator.oneStat) extra:string = engine.validator.OverlayStats;
engine.validator.overlaysStats overlays:(vector engine.validator.overlayStats) = engine.validator.OverlaysStats; engine.validator.overlaysStats overlays:(vector engine.validator.overlayStats) = engine.validator.OverlaysStats;
engine.validator.onePerfTimerStat time:int min:double avg:double max:double = engine.validator.OnePerfTimerStat; engine.validator.onePerfTimerStat time:int min:double avg:double max:double = engine.validator.OnePerfTimerStat;

Binary file not shown.

View file

@ -19,7 +19,8 @@
#pragma once #pragma once
#include "ton-types.h" #include "ton-types.h"
#include "auto/tl/ton_api.h" #include "auto/tl/ton_api.hpp"
#include "td/utils/overloaded.h"
namespace ton { namespace ton {
@ -53,4 +54,12 @@ inline ZeroStateIdExt create_zero_state_id(tl_object_ptr<ton_api::tonNode_zeroSt
return ZeroStateIdExt{B->workchain_, B->root_hash_, B->file_hash_}; return ZeroStateIdExt{B->workchain_, B->root_hash_, B->file_hash_};
} }
inline ShardIdFull create_shard_id(const tl_object_ptr<ton_api::tonNode_shardId> &s) {
return ShardIdFull{s->workchain_, static_cast<td::uint64>(s->shard_)};
}
inline tl_object_ptr<ton_api::tonNode_shardId> create_tl_shard_id(const ShardIdFull &s) {
return create_tl_object<ton_api::tonNode_shardId>(s.workchain, s.shard);
}
} // namespace ton } // namespace ton

View file

@ -51,6 +51,8 @@ using ValidatorSessionId = td::Bits256;
constexpr WorkchainId masterchainId = -1, basechainId = 0, workchainInvalid = 0x80000000; constexpr WorkchainId masterchainId = -1, basechainId = 0, workchainInvalid = 0x80000000;
constexpr ShardId shardIdAll = (1ULL << 63); constexpr ShardId shardIdAll = (1ULL << 63);
constexpr int max_shard_pfx_len = 60;
enum GlobalCapabilities { enum GlobalCapabilities {
capIhrEnabled = 1, capIhrEnabled = 1,
capCreateStatsEnabled = 2, capCreateStatsEnabled = 2,

View file

@ -22,27 +22,15 @@
namespace ton::validatorsession { namespace ton::validatorsession {
td::Result<td::BufferSlice> serialize_candidate(const tl_object_ptr<ton_api::validatorSession_candidate> &block, td::Result<td::BufferSlice> serialize_candidate(const tl_object_ptr<ton_api::validatorSession_candidate>& block,
bool compression_enabled) { bool compression_enabled) {
if (!compression_enabled) { if (!compression_enabled) {
return serialize_tl_object(block, true); return serialize_tl_object(block, true);
} }
vm::BagOfCells boc1, boc2; size_t decompressed_size;
TRY_STATUS(boc1.deserialize(block->data_)); TRY_RESULT(compressed, compress_candidate_data(block->data_, block->collated_data_, decompressed_size))
if (boc1.get_root_count() != 1) {
return td::Status::Error("block candidate should have exactly one root");
}
std::vector<td::Ref<vm::Cell>> roots = {boc1.get_root_cell()};
TRY_STATUS(boc2.deserialize(block->collated_data_));
for (int i = 0; i < boc2.get_root_count(); ++i) {
roots.push_back(boc2.get_root_cell(i));
}
TRY_RESULT(data, vm::std_boc_serialize_multi(std::move(roots), 2));
td::BufferSlice compressed = td::lz4_compress(data);
LOG(VALIDATOR_SESSION_DEBUG) << "Compressing block candidate: " << block->data_.size() + block->collated_data_.size()
<< " -> " << compressed.size();
return create_serialize_tl_object<ton_api::validatorSession_compressedCandidate>( return create_serialize_tl_object<ton_api::validatorSession_compressedCandidate>(
0, block->src_, block->round_, block->root_hash_, (int)data.size(), std::move(compressed)); 0, block->src_, block->round_, block->root_hash_, (int)decompressed_size, std::move(compressed));
} }
td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candidate(td::Slice data, td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candidate(td::Slice data,
@ -55,8 +43,34 @@ td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candi
if (f->decompressed_size_ > max_decompressed_data_size) { if (f->decompressed_size_ > max_decompressed_data_size) {
return td::Status::Error("decompressed size is too big"); return td::Status::Error("decompressed size is too big");
} }
TRY_RESULT(decompressed, td::lz4_decompress(f->data_, f->decompressed_size_)); TRY_RESULT(p, decompress_candidate_data(f->data_, f->decompressed_size_));
if (decompressed.size() != (size_t)f->decompressed_size_) { return create_tl_object<ton_api::validatorSession_candidate>(f->src_, f->round_, f->root_hash_, std::move(p.first),
std::move(p.second));
}
td::Result<td::BufferSlice> compress_candidate_data(td::Slice block, td::Slice collated_data,
size_t& decompressed_size) {
vm::BagOfCells boc1, boc2;
TRY_STATUS(boc1.deserialize(block));
if (boc1.get_root_count() != 1) {
return td::Status::Error("block candidate should have exactly one root");
}
std::vector<td::Ref<vm::Cell>> roots = {boc1.get_root_cell()};
TRY_STATUS(boc2.deserialize(collated_data));
for (int i = 0; i < boc2.get_root_count(); ++i) {
roots.push_back(boc2.get_root_cell(i));
}
TRY_RESULT(data, vm::std_boc_serialize_multi(std::move(roots), 2));
decompressed_size = data.size();
td::BufferSlice compressed = td::lz4_compress(data);
LOG(DEBUG) << "Compressing block candidate: " << block.size() + collated_data.size() << " -> " << compressed.size();
return compressed;
}
td::Result<std::pair<td::BufferSlice, td::BufferSlice>> decompress_candidate_data(td::Slice compressed,
int decompressed_size) {
TRY_RESULT(decompressed, td::lz4_decompress(compressed, decompressed_size));
if (decompressed.size() != (size_t)decompressed_size) {
return td::Status::Error("decompressed size mismatch"); return td::Status::Error("decompressed size mismatch");
} }
TRY_RESULT(roots, vm::std_boc_deserialize_multi(decompressed)); TRY_RESULT(roots, vm::std_boc_deserialize_multi(decompressed));
@ -66,10 +80,9 @@ td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candi
TRY_RESULT(block_data, vm::std_boc_serialize(roots[0], 31)); TRY_RESULT(block_data, vm::std_boc_serialize(roots[0], 31));
roots.erase(roots.begin()); roots.erase(roots.begin());
TRY_RESULT(collated_data, vm::std_boc_serialize_multi(std::move(roots), 31)); TRY_RESULT(collated_data, vm::std_boc_serialize_multi(std::move(roots), 31));
LOG(VALIDATOR_SESSION_DEBUG) << "Decompressing block candidate: " << f->data_.size() << " -> " LOG(DEBUG) << "Decompressing block candidate: " << compressed.size() << " -> "
<< block_data.size() + collated_data.size(); << block_data.size() + collated_data.size();
return create_tl_object<ton_api::validatorSession_candidate>(f->src_, f->round_, f->root_hash_, std::move(block_data), return std::make_pair(std::move(block_data), std::move(collated_data));
std::move(collated_data));
} }
} // namespace ton::validatorsession } // namespace ton::validatorsession

View file

@ -20,10 +20,15 @@
namespace ton::validatorsession { namespace ton::validatorsession {
td::Result<td::BufferSlice> serialize_candidate(const tl_object_ptr<ton_api::validatorSession_candidate> &block, td::Result<td::BufferSlice> serialize_candidate(const tl_object_ptr<ton_api::validatorSession_candidate>& block,
bool compression_enabled); bool compression_enabled);
td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candidate(td::Slice data, td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candidate(td::Slice data,
bool compression_enabled, bool compression_enabled,
int max_decompressed_data_size); int max_decompressed_data_size);
td::Result<td::BufferSlice> compress_candidate_data(td::Slice block, td::Slice collated_data,
size_t& decompressed_size);
td::Result<std::pair<td::BufferSlice, td::BufferSlice>> decompress_candidate_data(td::Slice compressed,
int decompressed_size);
} // namespace ton::validatorsession } // namespace ton::validatorsession

View file

@ -72,6 +72,11 @@ td::uint32 ValidatorSessionDescriptionImpl::get_max_priority() const {
return opts_.round_candidates - 1; return opts_.round_candidates - 1;
} }
td::uint32 ValidatorSessionDescriptionImpl::get_node_by_priority(td::uint32 round, td::uint32 priority) const {
CHECK(priority <= get_max_priority());
return (round + priority) % get_total_nodes();
}
ValidatorSessionCandidateId ValidatorSessionDescriptionImpl::candidate_id( ValidatorSessionCandidateId ValidatorSessionDescriptionImpl::candidate_id(
td::uint32 src_idx, ValidatorSessionRootHash root_hash, ValidatorSessionFileHash file_hash, td::uint32 src_idx, ValidatorSessionRootHash root_hash, ValidatorSessionFileHash file_hash,
ValidatorSessionCollatedDataFileHash collated_data_file_hash) const { ValidatorSessionCollatedDataFileHash collated_data_file_hash) const {

View file

@ -85,6 +85,7 @@ class ValidatorSessionDescription {
virtual ValidatorWeight get_total_weight() const = 0; virtual ValidatorWeight get_total_weight() const = 0;
virtual td::int32 get_node_priority(td::uint32 src_idx, td::uint32 round) const = 0; virtual td::int32 get_node_priority(td::uint32 src_idx, td::uint32 round) const = 0;
virtual td::uint32 get_max_priority() const = 0; virtual td::uint32 get_max_priority() const = 0;
virtual td::uint32 get_node_by_priority(td::uint32 round, td::uint32 priority) const = 0;
virtual td::uint32 get_unixtime(td::uint64 t) const = 0; virtual td::uint32 get_unixtime(td::uint64 t) const = 0;
virtual td::uint32 get_attempt_seqno(td::uint64 t) const = 0; virtual td::uint32 get_attempt_seqno(td::uint64 t) const = 0;
virtual td::uint32 get_self_idx() const = 0; virtual td::uint32 get_self_idx() const = 0;

View file

@ -114,6 +114,7 @@ class ValidatorSessionDescriptionImpl : public ValidatorSessionDescription {
} }
td::int32 get_node_priority(td::uint32 src_idx, td::uint32 round) const override; td::int32 get_node_priority(td::uint32 src_idx, td::uint32 round) const override;
td::uint32 get_max_priority() const override; td::uint32 get_max_priority() const override;
td::uint32 get_node_by_priority(td::uint32 round, td::uint32 priority) const override;
td::uint32 get_unixtime(td::uint64 ts) const override { td::uint32 get_unixtime(td::uint64 ts) const override {
return static_cast<td::uint32>(ts >> 32); return static_cast<td::uint32>(ts >> 32);
} }

View file

@ -21,6 +21,7 @@
#include "td/utils/crypto.h" #include "td/utils/crypto.h"
#include "candidate-serializer.h" #include "candidate-serializer.h"
#include "td/utils/overloaded.h" #include "td/utils/overloaded.h"
#include "ton/ton-tl.hpp"
namespace ton { namespace ton {

View file

@ -213,6 +213,28 @@ std::string CandidateShort::filename_short() const {
return PSTRING() << "candidate_" << block_id.workchain << "_" << s << "_" << block_id.seqno << "_" << hash().to_hex(); return PSTRING() << "candidate_" << block_id.workchain << "_" << s << "_" << block_id.seqno << "_" << hash().to_hex();
} }
CandidateRefShort CandidateRef::shortref() const {
return CandidateRefShort{block_id.id, hash()};
}
std::string CandidateRef::filename() const {
return PSTRING() << "candidateref_" << block_id.to_str();
}
std::string CandidateRef::filename_short() const {
char s[33];
sprintf(s, "%llx", static_cast<long long>(block_id.id.shard));
return PSTRING() << "candidateref_" << block_id.id.workchain << "_" << s << "_" << block_id.id.seqno << "_"
<< hash().to_hex();
}
std::string CandidateRefShort::filename_short() const {
char s[33];
sprintf(s, "%llx", static_cast<long long>(block_id.shard));
return PSTRING() << "candidateref_" << block_id.workchain << "_" << s << "_" << block_id.seqno << "_"
<< hash().to_hex();
}
BlockInfoShort BlockInfo::shortref() const { BlockInfoShort BlockInfo::shortref() const {
return BlockInfoShort{block_id.id, hash()}; return BlockInfoShort{block_id.id, hash()};
} }
@ -259,6 +281,9 @@ FileReference::FileReference(tl_object_ptr<ton_api::db_filedb_Key> key) {
ref_ = fileref::Candidate{PublicKey{key.id_->source_}, create_block_id(key.id_->id_), ref_ = fileref::Candidate{PublicKey{key.id_->source_}, create_block_id(key.id_->id_),
key.id_->collated_data_file_hash_}; key.id_->collated_data_file_hash_};
}, },
[&](const ton_api::db_filedb_key_candidateRef& key) {
ref_ = fileref::CandidateRef{create_block_id(key.id_)};
},
[&](const ton_api::db_filedb_key_blockInfo& key) { [&](const ton_api::db_filedb_key_blockInfo& key) {
ref_ = fileref::BlockInfo{create_block_id(key.block_id_)}; ref_ = fileref::BlockInfo{create_block_id(key.block_id_)};
})); }));

View file

@ -278,6 +278,38 @@ class Candidate {
FileHash collated_data_file_hash; FileHash collated_data_file_hash;
}; };
class CandidateRefShort {
public:
FileHash hash() const {
return hashv;
}
ShardIdFull shard() const {
return block_id.shard_full();
}
std::string filename_short() const;
BlockId block_id;
FileHash hashv;
};
class CandidateRef {
public:
tl_object_ptr<ton_api::db_filedb_Key> tl() const {
return create_tl_object<ton_api::db_filedb_key_candidateRef>(create_tl_block_id(block_id));
}
FileHash hash() const {
return create_hash_tl_object<ton_api::db_filedb_key_candidateRef>(create_tl_block_id(block_id));
}
ShardIdFull shard() const {
return block_id.shard_full();
}
CandidateRefShort shortref() const;
std::string filename() const;
std::string filename_short() const;
BlockIdExt block_id;
};
class BlockInfoShort { class BlockInfoShort {
public: public:
FileHash hash() const { FileHash hash() const {
@ -316,7 +348,7 @@ class FileReferenceShort {
private: private:
td::Variant<fileref::Empty, fileref::BlockShort, fileref::ZeroStateShort, fileref::PersistentStateShort, td::Variant<fileref::Empty, fileref::BlockShort, fileref::ZeroStateShort, fileref::PersistentStateShort,
fileref::ProofShort, fileref::ProofShort, fileref::ProofLinkShort, fileref::SignaturesShort, fileref::ProofShort, fileref::ProofShort, fileref::ProofLinkShort, fileref::SignaturesShort,
fileref::CandidateShort, fileref::BlockInfoShort> fileref::CandidateShort, fileref::CandidateRefShort, fileref::BlockInfoShort>
ref_; ref_;
public: public:
@ -340,7 +372,8 @@ class FileReferenceShort {
class FileReference { class FileReference {
private: private:
td::Variant<fileref::Empty, fileref::Block, fileref::ZeroState, fileref::PersistentState, fileref::Proof, td::Variant<fileref::Empty, fileref::Block, fileref::ZeroState, fileref::PersistentState, fileref::Proof,
fileref::Proof, fileref::ProofLink, fileref::Signatures, fileref::Candidate, fileref::BlockInfo> fileref::Proof, fileref::ProofLink, fileref::Signatures, fileref::Candidate, fileref::CandidateRef,
fileref::BlockInfo>
ref_; ref_;
public: public:

View file

@ -177,21 +177,21 @@ void RootDb::get_block_proof_link(ConstBlockHandle handle, td::Promise<td::Ref<P
} }
void RootDb::store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) { void RootDb::store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) {
auto source = PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}};
auto obj = create_serialize_tl_object<ton_api::db_candidate>( auto obj = create_serialize_tl_object<ton_api::db_candidate>(
PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}}.tl(), create_tl_block_id(candidate.id), source.tl(), create_tl_block_id(candidate.id), std::move(candidate.data), std::move(candidate.collated_data));
std::move(candidate.data), std::move(candidate.collated_data)); auto P = td::PromiseCreator::lambda(
[archive_db = archive_db_.get(), promise = std::move(promise), block_id = candidate.id, source,
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable { collated_file_hash = candidate.collated_file_hash](td::Result<td::Unit> R) mutable {
if (R.is_error()) { TRY_RESULT_PROMISE(promise, _, std::move(R));
promise.set_error(R.move_as_error()); td::actor::send_closure(archive_db, &ArchiveManager::add_temp_file_short, fileref::CandidateRef{block_id},
} else { create_serialize_tl_object<ton_api::db_candidate_id>(
promise.set_value(td::Unit()); source.tl(), create_tl_block_id(block_id), collated_file_hash),
} std::move(promise));
}); });
td::actor::send_closure(archive_db_, &ArchiveManager::add_temp_file_short, td::actor::send_closure(archive_db_, &ArchiveManager::add_temp_file_short,
fileref::Candidate{PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}}, candidate.id, fileref::Candidate{source, candidate.id, candidate.collated_file_hash}, std::move(obj),
candidate.collated_file_hash}, std::move(P));
std::move(obj), std::move(P));
} }
void RootDb::get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash, void RootDb::get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
@ -215,6 +215,17 @@ void RootDb::get_block_candidate(PublicKey source, BlockIdExt id, FileHash colla
fileref::Candidate{source, id, collated_data_file_hash}, std::move(P)); fileref::Candidate{source, id, collated_data_file_hash}, std::move(P));
} }
void RootDb::get_block_candidate_by_block_id(BlockIdExt id, td::Promise<BlockCandidate> promise) {
td::actor::send_closure(
archive_db_, &ArchiveManager::get_temp_file_short, fileref::CandidateRef{id},
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
TRY_RESULT_PROMISE(promise, data, std::move(R));
TRY_RESULT_PROMISE(promise, f, fetch_tl_object<ton_api::db_candidate_id>(data, true));
td::actor::send_closure(SelfId, &RootDb::get_block_candidate, PublicKey{f->source_}, create_block_id(f->id_),
f->collated_data_file_hash_, std::move(promise));
});
}
void RootDb::store_block_state(BlockHandle handle, td::Ref<ShardState> state, void RootDb::store_block_state(BlockHandle handle, td::Ref<ShardState> state,
td::Promise<td::Ref<ShardState>> promise) { td::Promise<td::Ref<ShardState>> promise) {
if (handle->moved_to_archive()) { if (handle->moved_to_archive()) {

View file

@ -58,6 +58,7 @@ class RootDb : public Db {
void store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) override; void store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) override;
void get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash, void get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
td::Promise<BlockCandidate> promise) override; td::Promise<BlockCandidate> promise) override;
void get_block_candidate_by_block_id(BlockIdExt id, td::Promise<BlockCandidate> promise) override;
void store_block_state(BlockHandle handle, td::Ref<ShardState> state, void store_block_state(BlockHandle handle, td::Ref<ShardState> state,
td::Promise<td::Ref<ShardState>> promise) override; td::Promise<td::Ref<ShardState>> promise) override;

View file

@ -50,9 +50,6 @@ class StateDb : public td::actor::Actor {
void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise); void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise);
void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise); void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise);
void update_db_version(td::uint32 version, td::Promise<td::Unit> promise);
void get_db_version(td::Promise<td::uint32> promise);
StateDb(td::actor::ActorId<RootDb> root_db, std::string path); StateDb(td::actor::ActorId<RootDb> root_db, std::string path);
void start_up() override; void start_up() override;

View file

@ -74,12 +74,12 @@ void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::Actor
td::Ref<ProofLink> rel_key_block_proof, bool skip_check_signatures = false); td::Ref<ProofLink> rel_key_block_proof, bool skip_check_signatures = false);
void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::actor::ActorId<ValidatorManager> manager, void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<BlockHandle> promise); td::Timestamp timeout, td::Promise<BlockHandle> promise);
void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, void run_validate_query(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
std::vector<BlockIdExt> prev, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<ValidateCandidateResult> promise, bool is_fake = false); td::Promise<ValidateCandidateResult> promise, bool is_fake = false);
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id, void run_collate_query(ShardIdFull shard, const BlockIdExt& min_masterchain_block_id, std::vector<BlockIdExt> prev,
std::vector<BlockIdExt> prev, Ed25519_PublicKey local_id, td::Ref<ValidatorSet> validator_set, Ed25519_PublicKey creator, td::Ref<ValidatorSet> validator_set,
td::Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager, td::Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<BlockCandidate> promise); td::Timestamp timeout, td::Promise<BlockCandidate> promise);
void run_collate_hardfork(ShardIdFull shard, const BlockIdExt& min_masterchain_block_id, std::vector<BlockIdExt> prev, void run_collate_hardfork(ShardIdFull shard, const BlockIdExt& min_masterchain_block_id, std::vector<BlockIdExt> prev,

View file

@ -27,7 +27,6 @@ set(TON_VALIDATOR_SOURCE
block.hpp block.hpp
candidates-buffer.hpp candidates-buffer.hpp
check-proof.hpp check-proof.hpp
collate-query-impl.h
collator-impl.h collator-impl.h
collator.h collator.h
config.hpp config.hpp

View file

@ -413,7 +413,36 @@ void AcceptBlockQuery::got_block_handle(BlockHandle handle) {
: handle_->inited_proof_link())) { : handle_->inited_proof_link())) {
finish_query(); finish_query();
return; return;
}
if (data_.is_null()) {
td::actor::send_closure(manager_, &ValidatorManager::get_candidate_data_by_block_id_from_db, id_, [SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
if (R.is_ok()) {
td::actor::send_closure(SelfId, &AcceptBlockQuery::got_block_candidate_data, R.move_as_ok());
} else {
td::actor::send_closure(SelfId, &AcceptBlockQuery::got_block_handle_cont);
}
});
} else {
got_block_handle_cont();
} }
}
void AcceptBlockQuery::got_block_candidate_data(td::BufferSlice data) {
auto r_block = create_block(id_, std::move(data));
if (r_block.is_error()) {
fatal_error("invalid block candidate data in db: " + r_block.error().to_string());
return;
}
data_ = r_block.move_as_ok();
VLOG(VALIDATOR_DEBUG) << "got block candidate data from db";
if (data_.not_null() && !precheck_header()) {
fatal_error("invalid block header in AcceptBlock");
return;
}
got_block_handle_cont();
}
void AcceptBlockQuery::got_block_handle_cont() {
if (data_.not_null() && !handle_->received()) { if (data_.not_null() && !handle_->received()) {
td::actor::send_closure( td::actor::send_closure(
manager_, &ValidatorManager::set_block_data, handle_, data_, [SelfId = actor_id(this)](td::Result<td::Unit> R) { manager_, &ValidatorManager::set_block_data, handle_, data_, [SelfId = actor_id(this)](td::Result<td::Unit> R) {

View file

@ -71,6 +71,8 @@ class AcceptBlockQuery : public td::actor::Actor {
void written_block_data(); void written_block_data();
void written_block_signatures(); void written_block_signatures();
void got_block_handle(BlockHandle handle); void got_block_handle(BlockHandle handle);
void got_block_candidate_data(td::BufferSlice data);
void got_block_handle_cont();
void written_block_info(); void written_block_info();
void got_block_data(td::Ref<BlockData> data); void got_block_data(td::Ref<BlockData> data);
void got_prev_state(td::Ref<ShardState> state); void got_prev_state(td::Ref<ShardState> state);

View file

@ -1,63 +0,0 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "validator/interfaces/validator-manager.h"
namespace ton {
namespace validator {
class CollateQuery : public td::actor::Actor {
public:
CollateQuery(ShardIdFull shard, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<BlockCandidate> promise);
CollateQuery(ShardIdFull shard, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, ZeroStateIdExt zero_state_id,
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<BlockCandidate> promise);
void alarm() override;
void abort_query(td::Status reason);
void finish_query();
void start_up() override;
void got_prev_state(td::Ref<MasterchainState> state);
void written_block_data();
void written_block_collated_data();
private:
ShardIdFull shard_;
UnixTime min_ts_;
BlockIdExt min_masterchain_block_id_;
std::vector<BlockIdExt> prev_;
ZeroStateIdExt zero_state_id_;
td::Ref<ValidatorSet> validator_set_;
td::actor::ActorId<ValidatorManager> manager_;
td::Timestamp timeout_;
td::Promise<BlockCandidate> promise_;
BlockCandidate candidate_;
UnixTime ts_;
};
} // namespace validator
} // namespace ton

View file

@ -65,7 +65,6 @@ class Collator final : public td::actor::Actor {
bool libraries_changed_{false}; bool libraries_changed_{false};
bool prev_key_block_exists_{false}; bool prev_key_block_exists_{false};
bool is_hardfork_{false}; bool is_hardfork_{false};
UnixTime min_ts;
BlockIdExt min_mc_block_id; BlockIdExt min_mc_block_id;
std::vector<BlockIdExt> prev_blocks; std::vector<BlockIdExt> prev_blocks;
std::vector<Ref<ShardState>> prev_states; std::vector<Ref<ShardState>> prev_states;
@ -89,10 +88,9 @@ class Collator final : public td::actor::Actor {
static constexpr bool shard_splitting_enabled = true; static constexpr bool shard_splitting_enabled = true;
public: public:
Collator(ShardIdFull shard, bool is_hardfork, td::uint32 min_ts, BlockIdExt min_masterchain_block_id, Collator(ShardIdFull shard, bool is_hardfork, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
std::vector<BlockIdExt> prev, Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id, Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id, Ref<CollatorOptions> collator_opts,
Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout, td::Promise<BlockCandidate> promise);
td::Promise<BlockCandidate> promise);
~Collator() override = default; ~Collator() override = default;
bool is_busy() const { bool is_busy() const {
return busy_; return busy_;

View file

@ -1,7 +1,7 @@
/* /*
This file is part of TON Blockchain Library. This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or the Free Software Foundation, either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
@ -66,7 +66,6 @@ static inline bool dbg(int c) {
* *
* @param shard The shard of the new block. * @param shard The shard of the new block.
* @param is_hardfork A boolean indicating whether the new block is a hardfork. * @param is_hardfork A boolean indicating whether the new block is a hardfork.
* @param min_ts The minimum UnixTime for the new block.
* @param min_masterchain_block_id The the minimum reference masterchain block. * @param min_masterchain_block_id The the minimum reference masterchain block.
* @param prev A vector of BlockIdExt representing the previous blocks. * @param prev A vector of BlockIdExt representing the previous blocks.
* @param validator_set A reference to the ValidatorSet. * @param validator_set A reference to the ValidatorSet.
@ -76,13 +75,12 @@ static inline bool dbg(int c) {
* @param timeout The timeout for the collator. * @param timeout The timeout for the collator.
* @param promise The promise to return the result. * @param promise The promise to return the result.
*/ */
Collator::Collator(ShardIdFull shard, bool is_hardfork, UnixTime min_ts, BlockIdExt min_masterchain_block_id, Collator::Collator(ShardIdFull shard, bool is_hardfork, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id, std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id,
Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager, Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<BlockCandidate> promise) td::Timestamp timeout, td::Promise<BlockCandidate> promise)
: shard_(shard) : shard_(shard)
, is_hardfork_(is_hardfork) , is_hardfork_(is_hardfork)
, min_ts(min_ts)
, min_mc_block_id{min_masterchain_block_id} , min_mc_block_id{min_masterchain_block_id}
, prev_blocks(std::move(prev)) , prev_blocks(std::move(prev))
, created_by_(collator_id) , created_by_(collator_id)

View file

@ -24,26 +24,7 @@
#include "vm/cells.h" #include "vm/cells.h"
namespace ton { namespace ton {
using td::Ref;
extern int collator_settings; // +1 = force want_split, +2 = force want_merge extern int collator_settings; // +1 = force want_split, +2 = force want_merge
class Collator : public td::actor::Actor {
protected:
Collator() = default;
public:
virtual ~Collator() = default;
static td::actor::ActorOwn<Collator> create_collator(
td::actor::ActorId<block::BlockDb> block_db,
ShardIdFull shard /* , td::actor::ActorId<ValidatorManager> validator_manager */);
virtual void generate_block_candidate(ShardIdFull shard, td::Promise<BlockCandidate> promise) = 0;
virtual td::Result<bool> register_external_message_cell(Ref<vm::Cell> ext_msg) = 0;
virtual td::Result<bool> register_external_message(td::Slice ext_msg_boc) = 0;
virtual td::Result<bool> register_ihr_message_cell(Ref<vm::Cell> ihr_msg) = 0;
virtual td::Result<bool> register_ihr_message(td::Slice ihr_msg_boc) = 0;
virtual td::Result<bool> register_shard_signatures_cell(Ref<vm::Cell> shard_blk_signatures) = 0;
virtual td::Result<bool> register_shard_signatures(td::Slice shard_blk_signatures_boc) = 0;
};
} // namespace ton } // namespace ton

View file

@ -133,9 +133,9 @@ void run_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures, td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures,
td::Ref<BlockSignatureSet> approve_signatures, bool send_broadcast, td::Ref<BlockSignatureSet> approve_signatures, bool send_broadcast,
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise) { td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise) {
td::actor::create_actor<AcceptBlockQuery>("accept", id, std::move(data), prev, std::move(validator_set), td::actor::create_actor<AcceptBlockQuery>(PSTRING() << "accept" << id.id.to_str(), id, std::move(data), prev,
std::move(signatures), std::move(approve_signatures), send_broadcast, std::move(validator_set), std::move(signatures),
manager, std::move(promise)) std::move(approve_signatures), send_broadcast, manager, std::move(promise))
.release(); .release();
} }
@ -192,7 +192,7 @@ void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::act
.release(); .release();
} }
void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, void run_validate_query(ShardIdFull shard, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set, std::vector<BlockIdExt> prev, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<ValidateCandidateResult> promise, bool is_fake) { td::Promise<ValidateCandidateResult> promise, bool is_fake) {
@ -205,14 +205,14 @@ void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_maste
static std::atomic<size_t> idx; static std::atomic<size_t> idx;
td::actor::create_actor<ValidateQuery>(PSTRING() << (is_fake ? "fakevalidate" : "validateblock") << shard.to_str() td::actor::create_actor<ValidateQuery>(PSTRING() << (is_fake ? "fakevalidate" : "validateblock") << shard.to_str()
<< ":" << (seqno + 1) << "#" << idx.fetch_add(1), << ":" << (seqno + 1) << "#" << idx.fetch_add(1),
shard, min_ts, min_masterchain_block_id, std::move(prev), std::move(candidate), shard, min_masterchain_block_id, std::move(prev), std::move(candidate),
std::move(validator_set), std::move(manager), timeout, std::move(promise), std::move(validator_set), std::move(manager), timeout, std::move(promise),
is_fake) is_fake)
.release(); .release();
} }
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id, void run_collate_query(ShardIdFull shard, const BlockIdExt& min_masterchain_block_id, std::vector<BlockIdExt> prev,
std::vector<BlockIdExt> prev, Ed25519_PublicKey collator_id, td::Ref<ValidatorSet> validator_set, Ed25519_PublicKey creator, td::Ref<ValidatorSet> validator_set,
td::Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager, td::Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<BlockCandidate> promise) { td::Timestamp timeout, td::Promise<BlockCandidate> promise) {
BlockSeqno seqno = 0; BlockSeqno seqno = 0;
@ -222,9 +222,8 @@ void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& m
} }
} }
td::actor::create_actor<Collator>(PSTRING() << "collate" << shard.to_str() << ":" << (seqno + 1), shard, false, td::actor::create_actor<Collator>(PSTRING() << "collate" << shard.to_str() << ":" << (seqno + 1), shard, false,
min_ts, min_masterchain_block_id, std::move(prev), std::move(validator_set), min_masterchain_block_id, std::move(prev), std::move(validator_set), creator,
collator_id, std::move(collator_opts), std::move(manager), timeout, std::move(collator_opts), std::move(manager), timeout, std::move(promise))
std::move(promise))
.release(); .release();
} }
@ -237,7 +236,7 @@ void run_collate_hardfork(ShardIdFull shard, const BlockIdExt& min_masterchain_b
seqno = p.seqno(); seqno = p.seqno();
} }
} }
td::actor::create_actor<Collator>(PSTRING() << "collate" << shard.to_str() << ":" << (seqno + 1), shard, true, 0, td::actor::create_actor<Collator>(PSTRING() << "collate" << shard.to_str() << ":" << (seqno + 1), shard, true,
min_masterchain_block_id, std::move(prev), td::Ref<ValidatorSet>{}, min_masterchain_block_id, std::move(prev), td::Ref<ValidatorSet>{},
Ed25519_PublicKey{Bits256::zero()}, td::Ref<CollatorOptions>{true}, Ed25519_PublicKey{Bits256::zero()}, td::Ref<CollatorOptions>{true},
std::move(manager), timeout, std::move(promise)) std::move(manager), timeout, std::move(promise))

View file

@ -373,7 +373,8 @@ td::Status MasterchainStateQ::mc_init() {
td::Status MasterchainStateQ::mc_reinit() { td::Status MasterchainStateQ::mc_reinit() {
auto res = block::ConfigInfo::extract_config( auto res = block::ConfigInfo::extract_config(
root_cell(), block::ConfigInfo::needStateRoot | block::ConfigInfo::needValidatorSet | root_cell(), block::ConfigInfo::needStateRoot | block::ConfigInfo::needValidatorSet |
block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks); block::ConfigInfo::needShardHashes | block::ConfigInfo::needPrevBlocks |
block::ConfigInfo::needWorkchainInfo);
cur_validators_.reset(); cur_validators_.reset();
next_validators_.reset(); next_validators_.reset();
if (res.is_error()) { if (res.is_error()) {
@ -519,15 +520,15 @@ bool MasterchainStateQ::check_old_mc_block_id(const ton::BlockIdExt& blkid, bool
return config_ && config_->check_old_mc_block_id(blkid, strict); return config_ && config_->check_old_mc_block_id(blkid, strict);
} }
td::uint32 MasterchainStateQ::min_split_depth(WorkchainId workchain_id) const { td::uint32 MasterchainStateQ::monitor_min_split_depth(WorkchainId workchain_id) const {
if (!config_) { if (!config_) {
return 0; return 0;
} }
auto wc_info = config_->get_workchain_info(workchain_id); auto wc_info = config_->get_workchain_info(workchain_id);
return wc_info.not_null() ? wc_info->actual_min_split : 0; return wc_info.not_null() ? wc_info->monitor_min_split : 0;
} }
td::uint32 MasterchainStateQ::soft_min_split_depth(WorkchainId workchain_id) const { td::uint32 MasterchainStateQ::min_split_depth(WorkchainId workchain_id) const {
if (!config_) { if (!config_) {
return 0; return 0;
} }
@ -564,5 +565,9 @@ BlockIdExt MasterchainStateQ::prev_key_block_id(BlockSeqno seqno) const {
return block_id; return block_id;
} }
bool MasterchainStateQ::is_key_state() const {
return config_ ? config_->is_key_state() : false;
}
} // namespace validator } // namespace validator
} // namespace ton } // namespace ton

View file

@ -120,8 +120,8 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
bool has_workchain(WorkchainId workchain) const { bool has_workchain(WorkchainId workchain) const {
return config_ && config_->has_workchain(workchain); return config_ && config_->has_workchain(workchain);
} }
td::uint32 monitor_min_split_depth(WorkchainId workchain_id) const override;
td::uint32 min_split_depth(WorkchainId workchain_id) const override; td::uint32 min_split_depth(WorkchainId workchain_id) const override;
td::uint32 soft_min_split_depth(WorkchainId workchain_id) const override;
BlockSeqno min_ref_masterchain_seqno() const override; BlockSeqno min_ref_masterchain_seqno() const override;
td::Status prepare() override; td::Status prepare() override;
ZeroStateIdExt get_zerostate_id() const { ZeroStateIdExt get_zerostate_id() const {
@ -137,6 +137,7 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
BlockIdExt last_key_block_id() const override; BlockIdExt last_key_block_id() const override;
BlockIdExt next_key_block_id(BlockSeqno seqno) const override; BlockIdExt next_key_block_id(BlockSeqno seqno) const override;
BlockIdExt prev_key_block_id(BlockSeqno seqno) const override; BlockIdExt prev_key_block_id(BlockSeqno seqno) const override;
bool is_key_state() const override;
MasterchainStateQ* make_copy() const override; MasterchainStateQ* make_copy() const override;
static td::Result<Ref<MasterchainStateQ>> fetch(const BlockIdExt& _id, td::BufferSlice _data, static td::Result<Ref<MasterchainStateQ>> fetch(const BlockIdExt& _id, td::BufferSlice _data,

View file

@ -57,7 +57,6 @@ std::string ErrorCtx::as_string() const {
* Constructs a ValidateQuery object. * Constructs a ValidateQuery object.
* *
* @param shard The shard of the block being validated. * @param shard The shard of the block being validated.
* @param min_ts The minimum allowed UnixTime for the block.
* @param min_masterchain_block_id The minimum allowed masterchain block reference for the block. * @param min_masterchain_block_id The minimum allowed masterchain block reference for the block.
* @param prev A vector of BlockIdExt representing the previous blocks. * @param prev A vector of BlockIdExt representing the previous blocks.
* @param candidate The BlockCandidate to be validated. * @param candidate The BlockCandidate to be validated.
@ -67,13 +66,12 @@ std::string ErrorCtx::as_string() const {
* @param promise The Promise to return the ValidateCandidateResult to. * @param promise The Promise to return the ValidateCandidateResult to.
* @param is_fake A boolean indicating if the validation is fake (performed when creating a hardfork). * @param is_fake A boolean indicating if the validation is fake (performed when creating a hardfork).
*/ */
ValidateQuery::ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, ValidateQuery::ValidateQuery(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
std::vector<BlockIdExt> prev, BlockCandidate candidate, Ref<ValidatorSet> validator_set, BlockCandidate candidate, Ref<ValidatorSet> validator_set,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<ValidateCandidateResult> promise, bool is_fake) td::Promise<ValidateCandidateResult> promise, bool is_fake)
: shard_(shard) : shard_(shard)
, id_(candidate.id) , id_(candidate.id)
, min_ts(min_ts)
, min_mc_block_id(min_masterchain_block_id) , min_mc_block_id(min_masterchain_block_id)
, prev_blocks(std::move(prev)) , prev_blocks(std::move(prev))
, block_candidate(std::move(candidate)) , block_candidate(std::move(candidate))
@ -87,7 +85,6 @@ ValidateQuery::ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_
, perf_timer_("validateblock", 0.1, [manager](double duration) { , perf_timer_("validateblock", 0.1, [manager](double duration) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "validateblock", duration); send_closure(manager, &ValidatorManager::add_perf_timer_stat, "validateblock", duration);
}) { }) {
proc_hash_.zero();
} }
/** /**
@ -709,7 +706,7 @@ void ValidateQuery::after_get_latest_mc_state(td::Result<std::pair<Ref<Mastercha
/** /**
* Callback function called after retrieving the masterchain state referenced int the block. * Callback function called after retrieving the masterchain state referenced int the block.
* *
* @param res The result of the masterchain state retrieval. * @param res The result of the masterchain state retrieval.
*/ */
void ValidateQuery::after_get_mc_state(td::Result<Ref<ShardState>> res) { void ValidateQuery::after_get_mc_state(td::Result<Ref<ShardState>> res) {
@ -1333,7 +1330,7 @@ bool ValidateQuery::compute_next_state() {
* Unpacks and merges the states of two previous blocks. * Unpacks and merges the states of two previous blocks.
* Used if the block is after_merge. * Used if the block is after_merge.
* Similar to Collator::unpack_merge_last_state() * Similar to Collator::unpack_merge_last_state()
* *
* @returns True if the unpacking and merging was successful, false otherwise. * @returns True if the unpacking and merging was successful, false otherwise.
*/ */
bool ValidateQuery::unpack_merge_prev_state() { bool ValidateQuery::unpack_merge_prev_state() {
@ -2334,7 +2331,7 @@ bool ValidateQuery::fix_all_processed_upto() {
* Adds trivials neighbor after merging two shards. * Adds trivials neighbor after merging two shards.
* Trivial neighbors are the two previous blocks. * Trivial neighbors are the two previous blocks.
* Almost the same as in Collator. * Almost the same as in Collator.
* *
* @returns True if the operation is successful, false otherwise. * @returns True if the operation is successful, false otherwise.
*/ */
bool ValidateQuery::add_trivial_neighbor_after_merge() { bool ValidateQuery::add_trivial_neighbor_after_merge() {
@ -2810,7 +2807,7 @@ bool ValidateQuery::precheck_one_account_update(td::ConstBitPtr acc_id, Ref<vm::
/** /**
* Pre-validates all account updates between the old and new state. * Pre-validates all account updates between the old and new state.
* *
* @returns True if the pre-check is successful, False otherwise. * @returns True if the pre-check is successful, False otherwise.
*/ */
bool ValidateQuery::precheck_account_updates() { bool ValidateQuery::precheck_account_updates() {
@ -3257,7 +3254,7 @@ bool ValidateQuery::precheck_one_message_queue_update(td::ConstBitPtr out_msg_id
/** /**
* Performs a pre-check on the difference between the old and new outbound message queues. * Performs a pre-check on the difference between the old and new outbound message queues.
* *
* @returns True if the pre-check is successful, false otherwise. * @returns True if the pre-check is successful, false otherwise.
*/ */
bool ValidateQuery::precheck_message_queue_update() { bool ValidateQuery::precheck_message_queue_update() {
@ -5033,12 +5030,10 @@ bool ValidateQuery::check_in_queue() {
neighbors_.at(kv->source).blk_.to_str()); neighbors_.at(kv->source).blk_.to_str());
} }
if (unprocessed) { if (unprocessed) {
inbound_queues_empty_ = false;
return true; return true;
} }
nb_out_msgs.next(); nb_out_msgs.next();
} }
inbound_queues_empty_ = true;
return true; return true;
} }
@ -5777,7 +5772,7 @@ bool ValidateQuery::scan_account_libraries(Ref<vm::Cell> orig_libs, Ref<vm::Cell
/** /**
* Checks if all necessary tick-tock smart contracts have been created. * Checks if all necessary tick-tock smart contracts have been created.
* Used in masterchain validation. * Used in masterchain validation.
* *
* @returns True if all necessary tick-tock transactions have been created, false otherwise. * @returns True if all necessary tick-tock transactions have been created, false otherwise.
*/ */
bool ValidateQuery::check_all_ticktock_processed() { bool ValidateQuery::check_all_ticktock_processed() {
@ -6919,6 +6914,7 @@ void ValidateQuery::written_candidate() {
void ValidateQuery::record_stats() { void ValidateQuery::record_stats() {
double work_time = work_timer_.elapsed(); double work_time = work_timer_.elapsed();
double cpu_work_time = cpu_work_timer_.elapsed(); double cpu_work_time = cpu_work_timer_.elapsed();
LOG(WARNING) << "validation took " << perf_timer_.elapsed() << "s";
LOG(WARNING) << "Validate query work time = " << work_time << "s, cpu time = " << cpu_work_time << "s"; LOG(WARNING) << "Validate query work time = " << work_time << "s, cpu time = " << cpu_work_time << "s";
td::actor::send_closure(manager, &ValidatorManager::record_validate_query_stats, block_candidate.id, work_time, td::actor::send_closure(manager, &ValidatorManager::record_validate_query_stats, block_candidate.id, work_time,
cpu_work_time); cpu_work_time);

View file

@ -117,7 +117,7 @@ class ValidateQuery : public td::actor::Actor {
} }
public: public:
ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev, ValidateQuery(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
BlockCandidate candidate, td::Ref<ValidatorSet> validator_set, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<ValidateCandidateResult> promise, bool is_fake = false); td::Promise<ValidateCandidateResult> promise, bool is_fake = false);
@ -127,7 +127,6 @@ class ValidateQuery : public td::actor::Actor {
int pending{0}; int pending{0};
const ShardIdFull shard_; const ShardIdFull shard_;
const BlockIdExt id_; const BlockIdExt id_;
UnixTime min_ts;
BlockIdExt min_mc_block_id; BlockIdExt min_mc_block_id;
std::vector<BlockIdExt> prev_blocks; std::vector<BlockIdExt> prev_blocks;
std::vector<Ref<ShardState>> prev_states; std::vector<Ref<ShardState>> prev_states;
@ -224,8 +223,7 @@ class ValidateQuery : public td::actor::Actor {
td::RefInt256 import_fees_; td::RefInt256 import_fees_;
ton::LogicalTime proc_lt_{0}, claimed_proc_lt_{0}, min_enq_lt_{~0ULL}; ton::LogicalTime proc_lt_{0}, claimed_proc_lt_{0}, min_enq_lt_{~0ULL};
ton::Bits256 proc_hash_, claimed_proc_hash_, min_enq_hash_; ton::Bits256 proc_hash_ = ton::Bits256::zero(), claimed_proc_hash_, min_enq_hash_;
bool inbound_queues_empty_{false};
std::vector<std::tuple<Bits256, LogicalTime, LogicalTime>> msg_proc_lt_; std::vector<std::tuple<Bits256, LogicalTime, LogicalTime>> msg_proc_lt_;
std::vector<std::tuple<Bits256, LogicalTime, LogicalTime>> msg_emitted_lt_; std::vector<std::tuple<Bits256, LogicalTime, LogicalTime>> msg_emitted_lt_;

View file

@ -46,6 +46,7 @@ class Db : public td::actor::Actor {
virtual void store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) = 0; virtual void store_block_candidate(BlockCandidate candidate, td::Promise<td::Unit> promise) = 0;
virtual void get_block_candidate(ton::PublicKey source, BlockIdExt id, FileHash collated_data_file_hash, virtual void get_block_candidate(ton::PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
td::Promise<BlockCandidate> promise) = 0; td::Promise<BlockCandidate> promise) = 0;
virtual void get_block_candidate_by_block_id(BlockIdExt id, td::Promise<BlockCandidate> promise) = 0;
virtual void store_block_state(BlockHandle handle, td::Ref<ShardState> state, virtual void store_block_state(BlockHandle handle, td::Ref<ShardState> state,
td::Promise<td::Ref<ShardState>> promise) = 0; td::Promise<td::Ref<ShardState>> promise) = 0;

View file

@ -70,14 +70,15 @@ class MasterchainState : virtual public ShardState {
virtual std::vector<td::Ref<McShardHash>> get_shards() const = 0; virtual std::vector<td::Ref<McShardHash>> get_shards() const = 0;
virtual td::Ref<McShardHash> get_shard_from_config(ShardIdFull shard) const = 0; virtual td::Ref<McShardHash> get_shard_from_config(ShardIdFull shard) const = 0;
virtual bool workchain_is_active(WorkchainId workchain_id) const = 0; virtual bool workchain_is_active(WorkchainId workchain_id) const = 0;
virtual td::uint32 monitor_min_split_depth(WorkchainId workchain_id) const = 0;
virtual td::uint32 min_split_depth(WorkchainId workchain_id) const = 0; virtual td::uint32 min_split_depth(WorkchainId workchain_id) const = 0;
virtual td::uint32 soft_min_split_depth(WorkchainId workchain_id) const = 0;
virtual BlockSeqno min_ref_masterchain_seqno() const = 0; virtual BlockSeqno min_ref_masterchain_seqno() const = 0;
virtual bool ancestor_is_valid(BlockIdExt id) const = 0; virtual bool ancestor_is_valid(BlockIdExt id) const = 0;
virtual ValidatorSessionConfig get_consensus_config() const = 0; virtual ValidatorSessionConfig get_consensus_config() const = 0;
virtual BlockIdExt last_key_block_id() const = 0; virtual BlockIdExt last_key_block_id() const = 0;
virtual BlockIdExt next_key_block_id(BlockSeqno seqno) const = 0; virtual BlockIdExt next_key_block_id(BlockSeqno seqno) const = 0;
virtual BlockIdExt prev_key_block_id(BlockSeqno seqno) const = 0; virtual BlockIdExt prev_key_block_id(BlockSeqno seqno) const = 0;
virtual bool is_key_state() const = 0;
virtual bool get_old_mc_block_id(ton::BlockSeqno seqno, ton::BlockIdExt& blkid, virtual bool get_old_mc_block_id(ton::BlockSeqno seqno, ton::BlockIdExt& blkid,
ton::LogicalTime* end_lt = nullptr) const = 0; ton::LogicalTime* end_lt = nullptr) const = 0;
virtual bool check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict = false) const = 0; virtual bool check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict = false) const = 0;

View file

@ -128,7 +128,7 @@ void ValidatorManagerImpl::sync_complete(td::Promise<td::Unit> promise) {
} }
Ed25519_PublicKey created_by{td::Bits256::zero()}; Ed25519_PublicKey created_by{td::Bits256::zero()};
td::as<td::uint32>(created_by.as_bits256().data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8); td::as<td::uint32>(created_by.as_bits256().data() + 32 - 4) = ((unsigned)std::time(nullptr) >> 8);
run_collate_query(shard_id, 0, last_masterchain_block_id_, prev, created_by, val_set, td::Ref<CollatorOptions>{true}, run_collate_query(shard_id, last_masterchain_block_id_, prev, created_by, val_set, td::Ref<CollatorOptions>{true},
actor_id(this), td::Timestamp::in(10.0), std::move(P)); actor_id(this), td::Timestamp::in(10.0), std::move(P));
} }
@ -152,7 +152,7 @@ void ValidatorManagerImpl::validate_fake(BlockCandidate candidate, std::vector<B
} }
}); });
auto shard = candidate.id.shard_full(); auto shard = candidate.id.shard_full();
run_validate_query(shard, 0, last, prev, std::move(candidate), std::move(val_set), actor_id(this), run_validate_query(shard, last, prev, std::move(candidate), std::move(val_set), actor_id(this),
td::Timestamp::in(10.0), std::move(P), true /* fake */); td::Timestamp::in(10.0), std::move(P), true /* fake */);
} }
@ -589,6 +589,11 @@ void ValidatorManagerImpl::get_block_candidate_from_db(PublicKey source, BlockId
td::actor::send_closure(db_, &Db::get_block_candidate, source, id, collated_data_file_hash, std::move(promise)); td::actor::send_closure(db_, &Db::get_block_candidate, source, id, collated_data_file_hash, std::move(promise));
} }
void ValidatorManagerImpl::get_candidate_data_by_block_id_from_db(BlockIdExt id, td::Promise<td::BufferSlice> promise) {
td::actor::send_closure(db_, &Db::get_block_candidate_by_block_id, id,
promise.wrap([](BlockCandidate &&b) { return std::move(b.data); }));
}
void ValidatorManagerImpl::get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) { void ValidatorManagerImpl::get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) {
td::actor::send_closure(db_, &Db::get_block_proof, std::move(handle), std::move(promise)); td::actor::send_closure(db_, &Db::get_block_proof, std::move(handle), std::move(promise));
} }

View file

@ -213,6 +213,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_shard_state_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override; void get_shard_state_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override;
void get_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash, void get_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
td::Promise<BlockCandidate> promise) override; td::Promise<BlockCandidate> promise) override;
void get_candidate_data_by_block_id_from_db(BlockIdExt id, td::Promise<td::BufferSlice> promise) override;
void get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) override; void get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) override;
void get_block_proof_from_db_short(BlockIdExt id, td::Promise<td::Ref<Proof>> promise) override; void get_block_proof_from_db_short(BlockIdExt id, td::Promise<td::Ref<Proof>> promise) override;
void get_block_proof_link_from_db(ConstBlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) override; void get_block_proof_link_from_db(ConstBlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) override;

View file

@ -415,6 +415,11 @@ void ValidatorManagerImpl::get_block_candidate_from_db(PublicKey source, BlockId
td::actor::send_closure(db_, &Db::get_block_candidate, source, id, collated_data_file_hash, std::move(promise)); td::actor::send_closure(db_, &Db::get_block_candidate, source, id, collated_data_file_hash, std::move(promise));
} }
void ValidatorManagerImpl::get_candidate_data_by_block_id_from_db(BlockIdExt id, td::Promise<td::BufferSlice> promise) {
td::actor::send_closure(db_, &Db::get_block_candidate_by_block_id, id,
promise.wrap([](BlockCandidate &&b) { return std::move(b.data); }));
}
void ValidatorManagerImpl::get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) { void ValidatorManagerImpl::get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) {
td::actor::send_closure(db_, &Db::get_block_proof, std::move(handle), std::move(promise)); td::actor::send_closure(db_, &Db::get_block_proof, std::move(handle), std::move(promise));
} }

View file

@ -258,6 +258,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_shard_state_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override; void get_shard_state_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override;
void get_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash, void get_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
td::Promise<BlockCandidate> promise) override; td::Promise<BlockCandidate> promise) override;
void get_candidate_data_by_block_id_from_db(BlockIdExt id, td::Promise<td::BufferSlice> promise) override;
void get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) override; void get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) override;
void get_block_proof_from_db_short(BlockIdExt id, td::Promise<td::Ref<Proof>> promise) override; void get_block_proof_from_db_short(BlockIdExt id, td::Promise<td::Ref<Proof>> promise) override;
void get_block_proof_link_from_db(ConstBlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) override; void get_block_proof_link_from_db(ConstBlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) override;

View file

@ -1035,6 +1035,16 @@ void ValidatorManagerImpl::get_block_candidate_from_db(PublicKey source, BlockId
td::actor::send_closure(db_, &Db::get_block_candidate, source, id, collated_data_file_hash, std::move(promise)); td::actor::send_closure(db_, &Db::get_block_candidate, source, id, collated_data_file_hash, std::move(promise));
} }
void ValidatorManagerImpl::get_candidate_data_by_block_id_from_db(BlockIdExt id, td::Promise<td::BufferSlice> promise) {
auto it = cached_block_candidates_.find(id);
if (it != cached_block_candidates_.end()) {
promise.set_result(it->second.data.clone());
return;
}
td::actor::send_closure(db_, &Db::get_block_candidate_by_block_id, id,
promise.wrap([](BlockCandidate &&b) { return std::move(b.data); }));
}
void ValidatorManagerImpl::get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) { void ValidatorManagerImpl::get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) {
td::actor::send_closure(db_, &Db::get_block_proof, std::move(handle), std::move(promise)); td::actor::send_closure(db_, &Db::get_block_proof, std::move(handle), std::move(promise));
} }
@ -2040,15 +2050,13 @@ void ValidatorManagerImpl::update_shards() {
auto it2 = next_validator_groups_.find(legacy_val_group_id); auto it2 = next_validator_groups_.find(legacy_val_group_id);
if (it2 != next_validator_groups_.end()) { if (it2 != next_validator_groups_.end()) {
if (!it2->second.actor.empty()) { if (!it2->second.actor.empty()) {
td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_, td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_);
last_masterchain_state_->get_unix_time());
} }
new_validator_groups_.emplace(val_group_id, std::move(it2->second)); new_validator_groups_.emplace(val_group_id, std::move(it2->second));
} else { } else {
auto G = create_validator_group(val_group_id, shard, val_set, key_seqno, opts, started_); auto G = create_validator_group(val_group_id, shard, val_set, key_seqno, opts, started_);
if (!G.empty()) { if (!G.empty()) {
td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_, td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_);
last_masterchain_state_->get_unix_time());
} }
new_validator_groups_.emplace(val_group_id, ValidatorGroupEntry{std::move(G), shard}); new_validator_groups_.emplace(val_group_id, ValidatorGroupEntry{std::move(G), shard});
} }
@ -2096,15 +2104,13 @@ void ValidatorManagerImpl::update_shards() {
auto it2 = next_validator_groups_.find(val_group_id); auto it2 = next_validator_groups_.find(val_group_id);
if (it2 != next_validator_groups_.end()) { if (it2 != next_validator_groups_.end()) {
if (!it2->second.actor.empty()) { if (!it2->second.actor.empty()) {
td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_, td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_);
last_masterchain_state_->get_unix_time());
} }
new_validator_groups_.emplace(val_group_id, std::move(it2->second)); new_validator_groups_.emplace(val_group_id, std::move(it2->second));
} else { } else {
auto G = create_validator_group(val_group_id, shard, val_set, key_seqno, opts, started_); auto G = create_validator_group(val_group_id, shard, val_set, key_seqno, opts, started_);
if (!G.empty()) { if (!G.empty()) {
td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_, td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_);
last_masterchain_state_->get_unix_time());
} }
new_validator_groups_.emplace(val_group_id, ValidatorGroupEntry{std::move(G), shard}); new_validator_groups_.emplace(val_group_id, ValidatorGroupEntry{std::move(G), shard});
} }

View file

@ -460,6 +460,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_shard_state_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override; void get_shard_state_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) override;
void get_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash, void get_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
td::Promise<BlockCandidate> promise) override; td::Promise<BlockCandidate> promise) override;
void get_candidate_data_by_block_id_from_db(BlockIdExt id, td::Promise<td::BufferSlice> promise) override;
void get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) override; void get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) override;
void get_block_proof_from_db_short(BlockIdExt id, td::Promise<td::Ref<Proof>> promise) override; void get_block_proof_from_db_short(BlockIdExt id, td::Promise<td::Ref<Proof>> promise) override;
void get_block_proof_link_from_db(ConstBlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) override; void get_block_proof_link_from_db(ConstBlockHandle handle, td::Promise<td::Ref<ProofLink>> promise) override;

View file

@ -202,10 +202,10 @@ void DownloadBlockNew::got_node_to_download(adnl::AdnlNodeIdShort node) {
} }
if (client_.empty()) { if (client_.empty()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_,
"get_proof", std::move(P), td::Timestamp::in(15.0), std::move(q), "get_block_full", std::move(P), td::Timestamp::in(15.0), std::move(q),
FullNode::max_proof_size() + FullNode::max_block_size() + 128, rldp_); FullNode::max_proof_size() + FullNode::max_block_size() + 128, rldp_);
} else { } else {
td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_prepare", td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_block_full",
create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(q)), create_serialize_tl_object_suffix<ton_api::tonNode_query>(std::move(q)),
td::Timestamp::in(15.0), std::move(P)); td::Timestamp::in(15.0), std::move(P));
} }

View file

@ -250,7 +250,7 @@ void ShardClient::build_shard_overlays() {
for (auto &x : v) { for (auto &x : v) {
auto shard = x->shard(); auto shard = x->shard();
if (opts_->need_monitor(shard)) { if (opts_->need_monitor(shard)) {
auto d = masterchain_state_->soft_min_split_depth(shard.workchain); auto d = masterchain_state_->monitor_min_split_depth(shard.workchain);
auto l = shard_prefix_length(shard.shard); auto l = shard_prefix_length(shard.shard);
if (l > d) { if (l > d) {
shard = shard_prefix(shard, d); shard = shard_prefix(shard, d);

View file

@ -51,9 +51,9 @@ void ValidatorGroup::generate_block_candidate(
return validatorsession::ValidatorSession::GeneratedCandidate{std::move(res), false}; return validatorsession::ValidatorSession::GeneratedCandidate{std::move(res), false};
})); }));
run_collate_query( run_collate_query(
shard_, min_ts_, min_masterchain_block_id_, prev_block_ids_, shard_, min_masterchain_block_id_, prev_block_ids_, Ed25519_PublicKey{local_id_full_.ed25519_value().raw()},
Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}, validator_set_, opts_->get_collator_options(), manager_, validator_set_, opts_->get_collator_options(), manager_, td::Timestamp::in(10.0),
td::Timestamp::in(10.0), [SelfId = actor_id(this), cache = cached_collated_block_](td::Result<BlockCandidate> R) { [SelfId = actor_id(this), cache = cached_collated_block_](td::Result<BlockCandidate> R) {
td::actor::send_closure(SelfId, &ValidatorGroup::generated_block_candidate, std::move(cache), std::move(R)); td::actor::send_closure(SelfId, &ValidatorGroup::generated_block_candidate, std::move(cache), std::move(R));
}); });
} }
@ -132,8 +132,8 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
} }
VLOG(VALIDATOR_DEBUG) << "validating block candidate " << next_block_id; VLOG(VALIDATOR_DEBUG) << "validating block candidate " << next_block_id;
block.id = next_block_id; block.id = next_block_id;
run_validate_query(shard_, min_ts_, min_masterchain_block_id_, prev_block_ids_, std::move(block), validator_set_, run_validate_query(shard_, min_masterchain_block_id_, prev_block_ids_, std::move(block), validator_set_, manager_,
manager_, td::Timestamp::in(15.0), std::move(P)); td::Timestamp::in(15.0), std::move(P));
} }
void ValidatorGroup::update_approve_cache(CacheKey key, UnixTime value) { void ValidatorGroup::update_approve_cache(CacheKey key, UnixTime value) {
@ -357,10 +357,9 @@ void ValidatorGroup::create_session() {
} }
} }
void ValidatorGroup::start(std::vector<BlockIdExt> prev, BlockIdExt min_masterchain_block_id, UnixTime min_ts) { void ValidatorGroup::start(std::vector<BlockIdExt> prev, BlockIdExt min_masterchain_block_id) {
prev_block_ids_ = prev; prev_block_ids_ = prev;
min_masterchain_block_id_ = min_masterchain_block_id; min_masterchain_block_id_ = min_masterchain_block_id;
min_ts_ = min_ts;
cached_collated_block_ = nullptr; cached_collated_block_ = nullptr;
approved_candidates_cache_.clear(); approved_candidates_cache_.clear();
started_ = true; started_ = true;

View file

@ -51,7 +51,7 @@ class ValidatorGroup : public td::actor::Actor {
BlockIdExt create_next_block_id(RootHash root_hash, FileHash file_hash) const; BlockIdExt create_next_block_id(RootHash root_hash, FileHash file_hash) const;
BlockId create_next_block_id_simple() const; BlockId create_next_block_id_simple() const;
void start(std::vector<BlockIdExt> prev, BlockIdExt min_masterchain_block_id, UnixTime min_ts); void start(std::vector<BlockIdExt> prev, BlockIdExt min_masterchain_block_id);
void create_session(); void create_session();
void destroy(); void destroy();
void start_up() override { void start_up() override {
@ -114,7 +114,6 @@ class ValidatorGroup : public td::actor::Actor {
std::vector<BlockIdExt> prev_block_ids_; std::vector<BlockIdExt> prev_block_ids_;
BlockIdExt min_masterchain_block_id_; BlockIdExt min_masterchain_block_id_;
UnixTime min_ts_;
td::Ref<ValidatorSet> validator_set_; td::Ref<ValidatorSet> validator_set_;
BlockSeqno last_key_block_seqno_; BlockSeqno last_key_block_seqno_;
@ -142,7 +141,7 @@ class ValidatorGroup : public td::actor::Actor {
void generated_block_candidate(std::shared_ptr<CachedCollatedBlock> cache, td::Result<BlockCandidate> R); void generated_block_candidate(std::shared_ptr<CachedCollatedBlock> cache, td::Result<BlockCandidate> R);
typedef std::tuple<td::Bits256, BlockIdExt, FileHash, FileHash> CacheKey; using CacheKey = std::tuple<td::Bits256, BlockIdExt, FileHash, FileHash>;
std::map<CacheKey, UnixTime> approved_candidates_cache_; std::map<CacheKey, UnixTime> approved_candidates_cache_;
void update_approve_cache(CacheKey key, UnixTime value); void update_approve_cache(CacheKey key, UnixTime value);

View file

@ -247,6 +247,7 @@ class ValidatorManagerInterface : public td::actor::Actor {
virtual void get_block_data_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) = 0; virtual void get_block_data_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<BlockData>> promise) = 0;
virtual void get_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash, virtual void get_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
td::Promise<BlockCandidate> promise) = 0; td::Promise<BlockCandidate> promise) = 0;
virtual void get_candidate_data_by_block_id_from_db(BlockIdExt id, td::Promise<td::BufferSlice> promise) = 0;
virtual void get_shard_state_from_db(ConstBlockHandle handle, td::Promise<td::Ref<ShardState>> promise) = 0; virtual void get_shard_state_from_db(ConstBlockHandle handle, td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void get_shard_state_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) = 0; virtual void get_shard_state_from_db_short(BlockIdExt block_id, td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) = 0; virtual void get_block_proof_from_db(ConstBlockHandle handle, td::Promise<td::Ref<Proof>> promise) = 0;