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)
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)
target_link_libraries(test-catchain overlay tdutils tdactor adnl adnltest rldp tl_api dht
catchain )

View file

@ -25,7 +25,7 @@ namespace ton {
namespace adnl {
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) {
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)
// { min_split <= max_split } { max_split <= 60 }
workchain#a6 enabled_since:uint32 actual_min_split:(## 8)
min_split:(## 8) max_split:(## 8) { actual_min_split <= min_split }
workchain#a6 enabled_since:uint32 monitor_min_split:(## 8)
min_split:(## 8) max_split:(## 8) { monitor_min_split <= min_split }
basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 }
zerostate_root_hash:bits256 zerostate_file_hash:bits256
version:uint32 format:(WorkchainFormat basic)
= WorkchainDescr;
workchain_v2#a7 enabled_since:uint32 actual_min_split:(## 8)
min_split:(## 8) max_split:(## 8) { actual_min_split <= min_split }
workchain_v2#a7 enabled_since:uint32 monitor_min_split:(## 8)
min_split:(## 8) max_split:(## 8) { monitor_min_split <= min_split }
basic:(## 1) active:Bool accept_msgs:Bool flags:(## 13) { flags = 0 }
zerostate_root_hash:bits256 zerostate_file_hash:bits256
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) {
enabled_since = info.enabled_since;
actual_min_split = info.actual_min_split;
monitor_min_split = info.monitor_min_split;
min_split = info.min_split;
max_split = info.max_split;
basic = info.basic;

View file

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

View file

@ -1214,4 +1214,35 @@ bool VmStorageStat::add_storage(const CellSlice& cs) {
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

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 {
bool special;
Cell::LevelMask level_mask;

View file

@ -22,12 +22,12 @@ namespace vm {
//
// 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();
if (!tree) {
return false;
}
tree->on_load(node_id_);
tree->on_load(node_id_, cell);
return true;
}
@ -111,8 +111,14 @@ void CellUsageTree::set_use_mark_for_is_loaded(bool 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;
if (cell_load_callback_) {
cell_load_callback_(cell);
}
}
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/logging.h"
#include <functional>
namespace vm {
class DataCell;
class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
public:
using NodeId = td::uint32;
@ -38,7 +42,7 @@ class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
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;
bool mark_path(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);
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:
struct Node {
bool is_loaded{false};
@ -68,8 +76,9 @@ class CellUsageTree : public std::enable_shared_from_this<CellUsageTree> {
};
bool use_mark_{false};
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);
};
} // namespace vm

View file

@ -66,6 +66,10 @@ class MerkleProofBuilder {
td::Result<Ref<Cell>> extract_proof() const;
bool extract_proof_to(Ref<Cell> &proof_root) 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

View file

@ -39,7 +39,7 @@ class UsageCell : public Cell {
// load interface
td::Result<LoadedCell> load_cell() const override {
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());
loaded_cell.tree_node = tree_node_;
}

View file

@ -260,6 +260,10 @@ class PublicKey {
td::BufferSlice export_as_slice() const;
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 {
CHECK(pub_key_.get_offset() == pub_key_.offset<pubkeys::Ed25519>());
return pub_key_.get<pubkeys::Ed25519>();

View file

@ -68,7 +68,7 @@ td::Status BroadcastSimple::run_checks() {
td::Status BroadcastSimple::distribute() {
auto B = serialize();
auto nodes = overlay_->get_neighbours(3);
auto nodes = overlay_->get_neighbours(overlay_->propagate_broadcast_to());
auto manager = overlay_->overlay_manager();
for (auto &n : nodes) {
@ -115,7 +115,8 @@ td::Status BroadcastSimple::run() {
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 data_hash = sha256_bits256(broadcast->data_.as_slice());
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 = std::move(tls.second);
auto nodes = overlay_->get_neighbours(5);
auto nodes = overlay_->get_neighbours(overlay_->propagate_broadcast_to());
auto manager = overlay_->overlay_manager();
for (auto &n : nodes) {

View file

@ -21,8 +21,14 @@
#include "auto/tl/ton_api.h"
#include "adnl/adnl-node-id.hpp"
#include "overlay/overlays.h"
#include "td/utils/SharedSlice.h"
#include "td/utils/buffer.h"
#include "td/utils/overloaded.h"
#include "keys/encryptor.h"
#include "td/utils/port/StdStreams.h"
#include "td/utils/unique_ptr.h"
#include <limits>
#include <memory>
namespace ton {
@ -30,18 +36,30 @@ namespace overlay {
class OverlayNode {
public:
explicit OverlayNode(adnl::AdnlNodeIdShort self_id, OverlayIdShort overlay) {
explicit OverlayNode(adnl::AdnlNodeIdShort self_id, OverlayIdShort overlay, td::uint32 flags) {
source_ = self_id;
overlay_ = overlay;
flags_ = flags;
version_ = static_cast<td::int32>(td::Clocks::system());
}
static td::Result<OverlayNode> create(const tl_object_ptr<ton_api::overlay_node> &node) {
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)
: 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,
td::int32 version, td::SharedSlice signature)
@ -64,10 +82,17 @@ class OverlayNode {
}
td::BufferSlice to_sign() const {
if (flags_ == 0) {
auto obj = create_tl_object<ton_api::overlay_node_toSign>(nullptr, overlay_.tl(), 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);
} 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) {
source_ = node_id;
@ -81,6 +106,9 @@ class OverlayNode {
td::int32 version() const {
return version_;
}
td::uint32 flags() const {
return flags_;
}
td::BufferSlice signature() const {
return signature_.clone_as_buffer_slice();
}
@ -103,15 +131,69 @@ class OverlayNode {
[&](const adnl::AdnlNodeIdFull &id) { obj->id_ = id.tl(); }));
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 {
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:
td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source_;
OverlayIdShort overlay_;
td::uint32 flags_;
td::int32 version_;
td::unique_ptr<OverlayMemberCertificate> cert_;
td::SharedSlice signature_;
static const OverlayMemberCertificate empty_certificate_;
};
} // namespace overlay

View file

@ -18,6 +18,7 @@
*/
#include "overlay-manager.h"
#include "auto/tl/ton_api.h"
#include "auto/tl/ton_api.hpp"
#include "overlay.h"
#include "adnl/utils.hpp"
@ -28,9 +29,9 @@
#include "td/db/RocksDb.h"
#include "td/utils/Status.h"
#include "td/utils/buffer.h"
#include "td/utils/overloaded.h"
#include "keys/encryptor.h"
#include "td/utils/port/Poll.h"
#include <vector>
@ -42,13 +43,13 @@ void OverlayManager::update_dht_node(td::actor::ActorId<dht::Dht> dht) {
dht_node_ = dht;
for (auto &X : overlays_) {
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,
td::actor::ActorOwn<Overlay> overlay) {
OverlayMemberCertificate cert, td::actor::ActorOwn<Overlay> overlay) {
auto it = overlays_.find(local_id);
VLOG(OVERLAY_INFO) << this << ": registering overlay " << overlay_id << "@" << local_id;
if (it == overlays_.end()) {
@ -58,17 +59,32 @@ void OverlayManager::register_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdS
td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id,
adnl::Adnl::int_to_bytestring(ton_api::overlay_query::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_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 =
td::PromiseCreator::lambda([id = overlays_[local_id][overlay_id].overlay.get()](td::Result<DbType::GetResult> R) {
R.ensure();
auto value = R.move_as_ok();
if (value.status == td::KeyValue::GetStatus::Ok) {
auto F = fetch_tl_object<ton_api::overlay_db_nodes>(std::move(value.value), true);
auto F = fetch_tl_object<ton_api::overlay_db_Nodes>(std::move(value.value), true);
F.ensure();
auto nodes = std::move(F.move_as_ok()->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());
@ -84,6 +100,10 @@ void OverlayManager::delete_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdSho
adnl::Adnl::int_to_bytestring(ton_api::overlay_message::ID));
td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_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);
}
}
@ -101,8 +121,8 @@ void OverlayManager::create_public_overlay_ex(adnl::AdnlNodeIdShort local_id, Ov
td::string scope, OverlayOptions opts) {
CHECK(!dht_node_.empty());
auto id = overlay_id.compute_short_id();
register_overlay(local_id, id,
Overlay::create(keyring_, adnl_, actor_id(this), dht_node_, local_id, std::move(overlay_id),
register_overlay(local_id, id, OverlayMemberCertificate{},
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)));
}
@ -110,65 +130,104 @@ void OverlayManager::create_private_overlay(adnl::AdnlNodeIdShort local_id, Over
std::vector<adnl::AdnlNodeIdShort> nodes,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules,
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();
register_overlay(local_id, id,
Overlay::create(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)));
register_overlay(local_id, id, OverlayMemberCertificate{},
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(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) {
auto R = fetch_tl_prefix<ton_api::overlay_message>(data, true);
if (R.is_error()) {
VLOG(OVERLAY_WARNING) << this << ": can not parse overlay message: " << R.move_as_error();
OverlayIdShort overlay_id;
tl_object_ptr<ton_api::overlay_messageExtra> extra;
auto R = fetch_tl_prefix<ton_api::overlay_messageWithExtra>(data, true);
if (R.is_ok()) {
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);
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;
}
auto it2 = it->second.find(OverlayIdShort{M->overlay_});
auto it2 = it->second.find(overlay_id);
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;
}
td::actor::send_closure(it2->second, &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::update_throughput_in_ctr, src, (td::uint32)data.size(), false);
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,
td::Promise<td::BufferSlice> promise) {
auto R = fetch_tl_prefix<ton_api::overlay_query>(data, true);
if (R.is_error()) {
OverlayIdShort overlay_id;
tl_object_ptr<ton_api::overlay_messageExtra> extra;
auto R = fetch_tl_prefix<ton_api::overlay_queryWithExtra>(data, true);
if (R.is_ok()) {
overlay_id = OverlayIdShort{R.ok()->overlay_};
extra = std::move(R.ok()->extra_);
} 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
<< "]: " << R.move_as_error();
<< "]: " << 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);
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));
return;
}
auto it2 = it->second.find(OverlayIdShort{M->overlay_});
auto it2 = it->second.find(overlay_id);
if (it2 == it->second.end()) {
VLOG(OVERLAY_NOTICE) << this << ": query to localid not in overlay " << M->overlay_ << "@" << dst << " from " << src;
promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad overlay_id " << M->overlay_));
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 " << overlay_id));
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::receive_query, src, std::move(data), std::move(promise));
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, &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,
@ -177,34 +236,63 @@ void OverlayManager::send_query_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdS
td::actor::ActorId<adnl::AdnlSenderInterface> via) {
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);
if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id);
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(
via, &adnl::AdnlSenderInterface::send_query_ex, src, dst, std::move(name), std::move(promise), timeout,
create_serialize_tl_object_suffix<ton_api::overlay_query>(query.as_slice(), overlay_id.tl()), max_answer_size);
auto extra_flags = extra->flags_;
td::BufferSlice serialized_query =
(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,
td::BufferSlice object, td::actor::ActorId<adnl::AdnlSenderInterface> via) {
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);
if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id);
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(
via, &adnl::AdnlSenderInterface::send_message, src, dst,
create_serialize_tl_object_suffix<ton_api::overlay_message>(object.as_slice(), overlay_id.tl()));
auto extra_flags = extra->flags_;
td::BufferSlice serialized_message =
(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) {
@ -218,7 +306,7 @@ void OverlayManager::send_broadcast_ex(adnl::AdnlNodeIdShort local_id, OverlayId
if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id);
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()) {
auto it2 = it->second.find(overlay_id);
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()) {
auto it2 = it->second.find(overlay_id);
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()) {
auto it2 = it->second.find(overlay_id);
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::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) {
auto it = overlays_.find(local_id);
if (it != overlays_.end()) {
if (it == overlays_.end()) {
promise.set_error(td::Status::Error(PSTRING() << "no such local id " << local_id));
return;
}
auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) {
td::actor::send_closure(it2->second, &Overlay::get_overlay_random_peers, max_peers, std::move(promise));
}
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,
@ -334,7 +453,7 @@ void OverlayManager::get_stats(td::Promise<tl_object_ptr<ton_api::engine_validat
for (auto &a : overlays_) {
for (auto &b : a.second) {
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) {
if (R.is_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);
}
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,
td::BufferSlice signature)
: 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>();
}
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 ton

View file

@ -55,9 +55,17 @@ class OverlayManager : public Overlays {
void create_public_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope,
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,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback,
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 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 {
@ -84,6 +92,11 @@ class OverlayManager : public Overlays {
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,
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,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) override;
@ -92,10 +105,12 @@ class OverlayManager : public Overlays {
td::Promise<td::BufferSlice> promise);
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);
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 {};
PrintId print_id() const {
@ -103,7 +118,11 @@ class OverlayManager : public Overlays {
}
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_;

View file

@ -16,89 +16,165 @@
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 "td/utils/Status.h"
#include "td/utils/Time.h"
#include "td/utils/port/signals.h"
#include <algorithm>
#include <vector>
namespace ton {
namespace overlay {
void OverlayImpl::del_peer(adnl::AdnlNodeIdShort id) {
auto P = peers_.get(id);
CHECK(P != nullptr);
void OverlayImpl::del_peer(const adnl::AdnlNodeIdShort &id) {
auto P = peer_list_.peers_.get(id);
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;
if (P->is_neighbour()) {
VLOG(OVERLAY_INFO) << this << ": deleting neighbour " << id;
del_from_neighbour_list(P);
}
peer_list_.peers_.remove(id);
peer_list_.bad_peers_.erase(id);
}
void OverlayImpl::del_from_neighbour_list(OverlayPeer *P) {
CHECK(P);
if (!P->is_neighbour()) {
return;
}
auto id = P->get_id();
bool deleted = false;
for (auto &n : neighbours_) {
auto &neighbours = peer_list_.neighbours_;
for (auto &n : neighbours) {
if (n == id) {
n = neighbours_[neighbours_.size() - 1];
neighbours_.resize(neighbours_.size() - 1);
n = neighbours[neighbours.size() - 1];
neighbours.resize(neighbours.size() - 1);
deleted = true;
break;
}
}
CHECK(deleted);
P->set_neighbour(false);
}
peers_.remove(id);
bad_peers_.erase(id);
update_neighbours(0);
}
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() {
if (!public_) {
if (overlay_type_ == OverlayType::FixedMemberList) {
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;
if (bad_peers_.empty()) {
if (peer_list_.bad_peers_.empty()) {
P = get_random_peer();
} else {
auto it = bad_peers_.upper_bound(next_bad_peer_);
if (it == bad_peers_.end()) {
it = bad_peers_.begin();
auto it = peer_list_.bad_peers_.upper_bound(peer_list_.next_bad_peer_);
if (it == peer_list_.bad_peers_.end()) {
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();
del_peer(id);
}
}
}
void OverlayImpl::do_add_peer(OverlayNode node) {
auto id = node.adnl_id_short();
auto V = 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();
peers_.insert(id, OverlayPeer(std::move(node)));
del_some_peers();
update_neighbours(0);
}
td::Status OverlayImpl::validate_peer_certificate(const adnl::AdnlNodeIdShort &node,
const OverlayMemberCertificate &cert) {
if (cert.empty()) {
if (is_persistent_node(node) || overlay_type_ == OverlayType::Public) {
return td::Status::OK();
}
return td::Status::Error(ErrorCode::protoviolation, "no member certificate found");
}
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) {
CHECK(public_);
do_add_peer(std::move(node));
td::Status OverlayImpl::validate_peer_certificate(const adnl::AdnlNodeIdShort &node,
ton_api::overlay_MemberCertificate *cert) {
OverlayMemberCertificate ncert(cert);
return validate_peer_certificate(node, ncert);
}
void OverlayImpl::add_peer_in(OverlayNode node) {
CHECK(public_);
td::Status OverlayImpl::validate_peer_certificate(const adnl::AdnlNodeIdShort &node,
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_) {
VLOG(OVERLAY_WARNING) << this << ": received node with bad overlay";
return;
}
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();
return;
}
@ -115,35 +191,80 @@ void OverlayImpl::add_peer_in(OverlayNode node) {
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) {
for (auto &node : peers) {
add_peer_in(std::move(node));
add_peer(std::move(node));
}
}
void OverlayImpl::add_peer(OverlayNode P) {
add_peer_in(std::move(P));
void OverlayImpl::add_peers(const tl_object_ptr<ton_api::overlay_nodes> &nodes) {
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) {
if (!public_) {
if (overlay_type_ == OverlayType::FixedMemberList) {
return;
}
if (OverlayPeer *p = peers_.get(peer)) {
if (OverlayPeer *p = peer_list_.peers_.get(peer)) {
p->on_ping_result(success);
if (p->is_alive()) {
bad_peers_.erase(peer);
peer_list_.bad_peers_.erase(peer);
} else {
bad_peers_.insert(peer);
peer_list_.bad_peers_.insert(peer);
}
}
}
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());
if (R.is_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;
}
auto res = R2.move_as_ok();
add_peers(R2.move_as_ok());
}
std::vector<OverlayNode> nodes;
for (auto &n : res->nodes_) {
auto N = OverlayNode::create(n);
if (N.is_ok()) {
nodes.emplace_back(N.move_as_ok());
void OverlayImpl::receive_random_peers_v2(adnl::AdnlNodeIdShort src, td::Result<td::BufferSlice> R) {
CHECK(overlay_type_ != OverlayType::FixedMemberList);
on_ping_result(src, R.is_ok());
if (R.is_error()) {
VLOG(OVERLAY_NOTICE) << this << ": failed getRandomPeersV2 query: " << R.move_as_error();
return;
}
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(std::move(nodes));
add_peers(R2.move_as_ok());
}
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());
}
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);
if (P) {
vec.emplace_back(P->get().tl());
if (P->has_full_id()) {
vec.emplace_back(P->get_node()->tl());
}
} else {
break;
}
@ -213,58 +345,110 @@ void OverlayImpl::send_random_peers(adnl::AdnlNodeIdShort src, td::Promise<td::B
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) {
if (peers_.size() == 0) {
if (peer_list_.peers_.size() == 0) {
return;
}
td::uint32 iter = 0;
while (iter < 10 && (nodes_to_change > 0 || neighbours_.size() < max_neighbours())) {
auto X = peers_.get_random();
while (iter++ < 10 && (nodes_to_change > 0 || peer_list_.neighbours_.size() < max_neighbours())) {
auto X = peer_list_.peers_.get_random();
if (!X) {
break;
}
if (X->get_id() == local_id_) {
iter++;
continue;
}
if (public_ && X->get_version() <= td::Clocks::system() - 600) {
if (X->get_version() <= td::Clocks::system() - Overlays::overlay_peer_ttl()) {
if (X->is_permanent_member()) {
del_from_neighbour_list(X);
} else {
auto id = X->get_id();
del_peer(id);
}
continue;
}
if (overlay_type_ == OverlayType::CertificatedMembers && !X->is_permanent_member() &&
X->certificate()->is_expired()) {
auto id = X->get_id();
del_peer(id);
continue;
}
if (X->get_node()->flags() & OverlayMemberFlags::DoNotReceiveBroadcasts) {
if (X->is_neighbour()) {
bool found = false;
for (auto &n : neighbours_) {
if (n == X->get_id()) {
n = *neighbours_.rbegin();
found = true;
break;
del_from_neighbour_list(X);
}
}
CHECK(found);
neighbours_.pop_back();
X->set_neighbour(false);
}
bad_peers_.erase(X->get_id());
peers_.remove(X->get_id());
continue;
}
if (X->is_neighbour()) {
iter++;
continue;
}
if (neighbours_.size() < max_neighbours()) {
if (peer_list_.neighbours_.size() < max_neighbours()) {
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);
} else {
CHECK(nodes_to_change > 0);
auto i = td::Random::fast(0, static_cast<td::uint32>(neighbours_.size()) - 1);
auto Y = peers_.get(neighbours_[i]);
auto i = td::Random::fast(0, static_cast<td::uint32>(peer_list_.neighbours_.size()) - 1);
auto Y = peer_list_.peers_.get(peer_list_.neighbours_[i]);
CHECK(Y != nullptr);
CHECK(Y->is_neighbour());
Y->set_neighbour(false);
neighbours_[i] = X->get_id();
peer_list_.neighbours_[i] = X->get_id();
X->set_neighbour(true);
nodes_to_change--;
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) {
size_t skip_bad = 3;
while (peers_.size() > (only_alive ? bad_peers_.size() : 0)) {
auto P = peers_.get_random();
if (public_ && P->get_version() + 3600 < td::Clocks::system()) {
OverlayPeer *res = nullptr;
while (!res && peer_list_.peers_.size() > (only_alive ? peer_list_.bad_peers_.size() : 0)) {
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();
del_peer(P->get_id());
continue;
@ -290,18 +476,19 @@ OverlayPeer *OverlayImpl::get_random_peer(bool only_alive) {
continue;
}
}
return P;
res = P;
}
return nullptr;
update_neighbours(0);
return res;
}
void OverlayImpl::get_overlay_random_peers(td::uint32 max_peers,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) {
std::vector<adnl::AdnlNodeIdShort> v;
auto t = td::Clocks::system();
while (v.size() < max_peers && v.size() < peers_.size() - bad_peers_.size()) {
auto P = peers_.get_random();
if (public_ && P->get_version() + 3600 < t) {
while (v.size() < max_peers && v.size() < peer_list_.peers_.size() - peer_list_.bad_peers_.size()) {
auto P = peer_list_.peers_.get_random();
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();
del_peer(P->get_id());
} else if (P->is_alive()) {
@ -317,20 +504,225 @@ void OverlayImpl::get_overlay_random_peers(td::uint32 max_peers,
}
}
}
update_neighbours(0);
promise.set_result(std::move(v));
}
void OverlayImpl::receive_nodes_from_db(tl_object_ptr<ton_api::overlay_nodes> tl_nodes) {
if (public_) {
std::vector<OverlayNode> nodes;
for (auto &n : tl_nodes->nodes_) {
auto N = OverlayNode::create(n);
if (N.is_ok()) {
nodes.emplace_back(N.move_as_ok());
if (overlay_type_ != OverlayType::FixedMemberList) {
add_peers(tl_nodes);
}
}
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

View file

@ -18,6 +18,7 @@
*/
#include "auto/tl/ton_api.h"
#include "td/utils/Random.h"
#include "common/delay.h"
#include "adnl/utils.hpp"
#include "dht/dht.h"
@ -26,41 +27,61 @@
#include "auto/tl/ton_api.hpp"
#include "keys/encryptor.h"
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/port/signals.h"
#include <limits>
namespace ton {
namespace overlay {
td::actor::ActorOwn<Overlay> Overlay::create(td::actor::ActorId<keyring::Keyring> keyring,
const OverlayMemberCertificate OverlayNode::empty_certificate_{};
td::actor::ActorOwn<Overlay> Overlay::create_public(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::unique_ptr<Overlays::Callback> callback,
td::actor::ActorId<dht::Dht> dht_node,
adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Overlays::Callback> callback,
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), true, std::vector<adnl::AdnlNodeIdShort>(),
std::move(callback), std::move(rules), scope, 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));
}
td::actor::ActorOwn<Overlay> Overlay::create(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::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules,
std::string scope) {
td::actor::ActorOwn<Overlay> Overlay::create_private(
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::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), false, std::move(nodes), std::move(callback),
std::move(rules), std::move(scope));
std::move(overlay_id), OverlayType::FixedMemberList, std::move(nodes),
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));
}
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,
adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, bool pub,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Overlays::Callback> callback,
adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, OverlayType overlay_type,
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)
: keyring_(keyring)
, adnl_(adnl)
@ -69,37 +90,28 @@ OverlayImpl::OverlayImpl(td::actor::ActorId<keyring::Keyring> keyring, td::actor
, local_id_(local_id)
, id_full_(std::move(overlay_id))
, callback_(std::move(callback))
, public_(pub)
, overlay_type_(overlay_type)
, rules_(std::move(rules))
, scope_(scope)
, announce_self_(opts.announce_self_)
, frequent_dht_lookup_(opts.frequent_dht_lookup_) {
, opts_(std::move(opts)) {
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) {
CHECK(!public_);
auto X = OverlayNode{node, overlay_id_};
do_add_peer(std::move(X));
}
update_root_member_list(std::move(nodes), std::move(root_public_keys), std::move(cert));
update_neighbours(static_cast<td::uint32>(nodes.size()));
}
void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getRandomPeers &query,
td::Promise<td::BufferSlice> promise) {
if (public_) {
if (overlay_type_ != OverlayType::FixedMemberList) {
VLOG(OVERLAY_DEBUG) << this << ": received " << query.peers_->nodes_.size() << " nodes from " << src
<< " in getRandomPeers query";
std::vector<OverlayNode> nodes;
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));
add_peers(query.peers_);
send_random_peers(src, std::move(promise));
} else {
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,
td::Promise<td::BufferSlice> promise) {
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) {
if (!public_) {
auto P = peers_.get(src);
if (P == nullptr) {
void OverlayImpl::receive_query(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
td::BufferSlice data, td::Promise<td::BufferSlice> promise) {
if (!is_valid_peer(src, extra ? extra->certificate_.get() : nullptr)) {
VLOG(OVERLAY_WARNING) << this << ": received query in private overlay from unknown source " << src;
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "overlay is private"));
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "overlay is not public"));
return;
}
} else {
on_ping_result(src, true);
}
auto R = fetch_tl_object<ton_api::Function>(data.clone(), true);
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,
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));
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
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));
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
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));
}
@ -188,6 +219,7 @@ 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) {
return td::Status::OK(); // disable this logic for now
auto it = fec_broadcasts_.find(msg->hash_);
if (it != fec_broadcasts_.end()) {
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,
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_);
if (it != fec_broadcasts_.end()) {
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();
}
void OverlayImpl::receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data) {
if (!public_) {
if (peers_.get(src) == nullptr) {
VLOG(OVERLAY_WARNING) << this << ": received query in private overlay from unknown source " << src;
void OverlayImpl::receive_message(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
td::BufferSlice data) {
if (!is_valid_peer(src, extra ? extra->certificate_.get() : nullptr)) {
VLOG(OVERLAY_WARNING) << this << ": received message in private overlay from unknown source " << src;
return;
}
} else {
on_ping_result(src, true);
}
auto X = fetch_tl_object<ton_api::overlay_Broadcast>(data.clone(), true);
if (X.is_error()) {
VLOG(OVERLAY_DEBUG) << this << ": received custom message";
@ -245,11 +276,11 @@ void OverlayImpl::receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice dat
void OverlayImpl::alarm() {
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();
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_in_bytes = static_cast<td::uint32>(peer.throughput_in_bytes_ctr / t_elapsed);
@ -274,14 +305,21 @@ void OverlayImpl::alarm() {
last_throughput_update_ = td::Timestamp::now();
}
if (public_) {
if (peers_.size() > 0) {
if (overlay_type_ != OverlayType::FixedMemberList) {
if (has_valid_membership_certificate()) {
auto P = get_random_peer();
if (P) {
if (overlay_type_ == OverlayType::Public) {
send_random_peers(P->get_id(), {});
} else {
send_random_peers_v2(P->get_id(), {});
}
}
if (next_dht_query_ && next_dht_query_.is_in_past()) {
} 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() && overlay_type_ == OverlayType::Public) {
next_dht_query_ = td::Timestamp::never();
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));
@ -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},
std::move(callback), std::move(on_finish));
}
if (update_db_at_.is_in_past()) {
if (peers_.size() > 0) {
if (update_db_at_.is_in_past() && overlay_type_ == OverlayType::Public) {
std::vector<OverlayNode> vec;
for (td::uint32 i = 0; i < 20; i++) {
auto P = get_random_peer();
if (!P) {
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));
}
update_db_at_ = td::Timestamp::in(60.0);
}
update_neighbours(0);
alarm_timestamp() = td::Timestamp::in(1.0);
} else {
update_neighbours(0);
@ -315,7 +354,7 @@ void OverlayImpl::alarm() {
}
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);
if (R.is_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) {
if (!public_) {
if (overlay_type_ != OverlayType::Public) {
return;
}
@ -418,21 +457,57 @@ void OverlayImpl::bcast_gc() {
CHECK(delivered_broadcasts_.size() == bcast_lru_.size());
}
void OverlayImpl::send_message_to_neighbours(td::BufferSlice data) {
for (auto &n : neighbours_) {
td::actor::send_closure(manager_, &OverlayManager::send_message, n, local_id_, overlay_id_, data.clone());
void OverlayImpl::wait_neighbours_not_empty(td::Promise<td::Unit> promise, int max_retries) {
if (!peer_list_.neighbours_.empty()) {
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) {
if (!has_valid_membership_certificate()) {
VLOG(OVERLAY_WARNING) << "member certificate is invalid, valid_until="
<< 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) {
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) {
@ -450,6 +525,22 @@ td::Status OverlayImpl::check_date(td::uint32 date) {
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,
bool is_fec) {
if (size == 0) {
@ -457,7 +548,7 @@ BroadcastCheckResult OverlayImpl::check_source_eligible(PublicKey source, const
}
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) {
return r;
}
@ -492,10 +583,11 @@ void OverlayImpl::register_fec_broadcast(std::unique_ptr<BroadcastFec> bcast) {
}
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 P = td::PromiseCreator::lambda([oid = print_id(), s = std::move(s), promise = std::move(promise)](
td::Result<std::pair<td::BufferSlice, PublicKey>> R) mutable {
auto P = td::PromiseCreator::lambda(
[oid = print_id(), s = std::move(s), cert = peer_list_.cert_,
promise = std::move(promise)](td::Result<std::pair<td::BufferSlice, PublicKey>> R) mutable {
if (R.is_error()) {
auto S = R.move_as_error();
LOG(ERROR) << oid << ": failed to get self node: " << S;
@ -505,6 +597,7 @@ void OverlayImpl::get_self_node(td::Promise<OverlayNode> promise) {
auto V = R.move_as_ok();
s.update_signature(std::move(V.first));
s.update_adnl_id(adnl::AdnlNodeIdFull{V.second});
s.update_certificate(std::move(cert));
promise.set_value(std::move(s));
});
@ -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));
}
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) {
{
auto it = broadcasts_.find(hash);
@ -630,7 +712,7 @@ void OverlayImpl::get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_
res->overlay_id_ = overlay_id_.bits256_value();
res->overlay_id_full_ = id_full_.pubkey().tl();
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>();
node_obj->adnl_id_ = key.bits256_value();
node_obj->t_out_bytes_ = peer.throughput_out_bytes;
@ -647,13 +729,30 @@ void OverlayImpl::get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_
node_obj->bdcst_errors_ = peer.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->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()));
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

View file

@ -18,6 +18,7 @@
*/
#pragma once
#include "auto/tl/ton_api.h"
#include "td/utils/buffer.h"
#include "td/utils/int_types.h"
@ -37,24 +38,29 @@ class Overlay : public td::actor::Actor {
using BroadcastDataHash = td::Bits256;
using BroadcastPartHash = td::Bits256;
static td::actor::ActorOwn<Overlay> create(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::unique_ptr<Overlays::Callback> callback,
OverlayPrivacyRules rules, td::string scope, OverlayOptions opts = {});
static td::actor::ActorOwn<Overlay> create(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::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules,
std::string scope);
static td::actor::ActorOwn<Overlay> create_public(
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::unique_ptr<Overlays::Callback> callback, OverlayPrivacyRules rules,
td::string scope, OverlayOptions opts = {});
static td::actor::ActorOwn<Overlay> create_private(
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::unique_ptr<Overlays::Callback> callback,
OverlayPrivacyRules rules, std::string scope, OverlayOptions opts = {});
static td::actor::ActorOwn<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 = {});
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_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) = 0;
virtual void receive_message(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
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_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;
@ -64,12 +70,17 @@ class Overlay : public td::actor::Actor {
virtual void add_certificate(PublicKeyHash key, std::shared_ptr<Certificate>) = 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_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 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_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 subscribe(std::unique_ptr<Overlays::Callback> callback) = 0;
virtual void forget_peer(adnl::AdnlNodeIdShort peer_id) = 0;
};
} // namespace overlay

View file

@ -18,11 +18,15 @@
*/
#pragma once
#include <any>
#include <memory>
#include <vector>
#include <map>
#include <set>
#include <unordered_set>
#include <queue>
#include "adnl/adnl-node-id.hpp"
#include "overlay.h"
#include "overlay-manager.h"
#include "overlay-fec.hpp"
@ -32,6 +36,9 @@
#include "td/utils/DecTree.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 "fec/fec.h"
@ -40,6 +47,8 @@
#include "auto/tl/ton_api.h"
#include "auto/tl/ton_api.hpp"
#include "td/utils/port/signals.h"
#include "tl-utils/common-utils.hpp"
namespace ton {
@ -58,15 +67,17 @@ class OverlayPeer {
adnl::AdnlNodeIdFull get_full_id() const {
return node_.adnl_id_full();
}
OverlayNode get() const {
return node_.clone();
const OverlayNode *get_node() const {
return &node_;
}
void update(OverlayNode node) {
CHECK(get_id() == node.adnl_id_short());
if (node.version() > node_.version()) {
node_ = std::move(node);
node_.update(std::move(node));
}
void update_certificate(OverlayMemberCertificate cert) {
node_.update_certificate(std::move(cert));
}
OverlayPeer(OverlayNode node) : node_(std::move(node)) {
id_ = node_.adnl_id_short();
}
@ -95,6 +106,26 @@ class OverlayPeer {
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_in_bytes = 0;
@ -122,6 +153,7 @@ class OverlayPeer {
bool is_neighbour_ = false;
size_t missed_pings_ = 0;
bool is_alive_ = true;
bool is_permanent_member_ = false;
td::Timestamp last_ping_at_ = td::Timestamp::now();
};
@ -129,19 +161,23 @@ class OverlayImpl : public Overlay {
public:
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,
adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, bool pub,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Overlays::Callback> callback,
OverlayPrivacyRules rules, td::string scope = "{ \"type\": \"undefined\" }", OverlayOptions opts = {});
adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id, OverlayType overlay_type,
std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
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 {
dht_node_ = dht;
}
void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data) override;
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise<td::BufferSlice> promise) override;
void receive_message(adnl::AdnlNodeIdShort src, tl_object_ptr<ton_api::overlay_messageExtra> extra,
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_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 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);
@ -150,7 +186,7 @@ class OverlayImpl : public Overlay {
update_throughput_at_ = td::Timestamp::in(50.0);
last_throughput_update_ = td::Timestamp::now();
if (public_) {
if (overlay_type_ == OverlayType::Public) {
update_db_at_ = td::Timestamp::in(60.0);
}
alarm_timestamp() = td::Timestamp::in(1);
@ -158,13 +194,17 @@ class OverlayImpl : public Overlay {
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_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_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_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 set_privacy_rules(OverlayPrivacyRules rules) override;
void add_certificate(PublicKeyHash key, std::shared_ptr<Certificate> cert) override {
certs_[key] = std::move(cert);
}
void update_member_certificate(OverlayMemberCertificate cert) override;
void receive_dht_nodes(dht::DhtValue v);
void dht_lookup_finished(td::Status S);
@ -188,6 +228,8 @@ class OverlayImpl : public Overlay {
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(const PublicKeyHash &source, const Certificate *cert, td::uint32 size,
bool is_fec);
td::Status check_delivered(BroadcastHash hash);
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,
td::uint32 flags, td::BufferSlice part, td::uint32 seqno, fec::FecType fec_type,
td::uint32 date);
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;
}
}
std::vector<adnl::AdnlNodeIdShort> get_neighbours(td::uint32 max_size = 0) const;
td::actor::ActorId<OverlayManager> overlay_manager() const {
return manager_;
}
@ -237,39 +269,59 @@ class OverlayImpl : public Overlay {
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 {
auto out_peer = peers_.get(peer_id);
if(out_peer) {
out_peer->throughput_out_bytes_ctr += msg_size;
out_peer->throughput_out_packets_ctr++;
void update_throughput_out_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) override;
if(is_query)
{
out_peer->last_out_query_at = td::Timestamp::now();
void update_throughput_in_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) override;
void update_peer_ip_str(adnl::AdnlNodeIdShort peer_id, td::string ip_str) override;
void update_root_member_list(std::vector<adnl::AdnlNodeIdShort> nodes, std::vector<PublicKeyHash> root_public_keys,
OverlayMemberCertificate cert) override;
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 {
return 1000;
}
td::uint32 max_fec_bcasts() const {
return 20;
}
td::uint32 max_sources() const {
return 10;
}
td::uint32 max_encryptors() const {
return 16;
}
void update_throughput_in_ctr(adnl::AdnlNodeIdShort peer_id, td::uint32 msg_size, bool is_query) override {
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_neighbours() const {
return opts_.max_neighbours_;
}
void update_peer_ip_str(adnl::AdnlNodeIdShort peer_id, td::string ip_str) override {
auto fpeer = peers_.get(peer_id);
if(fpeer) {
fpeer->ip_addr_str = ip_str;
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:
template <class T>
void process_query(adnl::AdnlNodeIdShort src, T &query, td::Promise<td::BufferSlice> promise) {
@ -278,6 +330,8 @@ class OverlayImpl : public Overlay {
void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getRandomPeers &query,
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,
td::Promise<td::BufferSlice> promise);
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_unicast> msg);
void do_add_peer(OverlayNode node);
void add_peer_in_cont(OverlayNode node);
void add_peer_in(OverlayNode node);
td::Status validate_peer_certificate(const adnl::AdnlNodeIdShort &node, const OverlayMemberCertificate &cert);
td::Status validate_peer_certificate(const adnl::AdnlNodeIdShort &node, const OverlayMemberCertificate *cert);
td::Status validate_peer_certificate(const adnl::AdnlNodeIdShort &node, ton_api::overlay_MemberCertificate *cert);
void add_peer(OverlayNode node);
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_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);
bool is_root_public_key(const PublicKeyHash &key) const;
bool has_good_peers() const;
size_t neighbours_cnt() const;
void finish_dht_query() {
if (!next_dht_store_query_) {
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));
} else {
next_dht_query_ = next_dht_store_query_;
@ -322,14 +384,11 @@ class OverlayImpl : public Overlay {
OverlayIdFull id_full_;
OverlayIdShort overlay_id_;
td::DecTree<adnl::AdnlNodeIdShort, OverlayPeer> peers_;
td::Timestamp next_dht_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_throughput_at_;
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_;
@ -337,7 +396,6 @@ class OverlayImpl : public Overlay {
std::map<BroadcastHash, std::unique_ptr<BroadcastFec>> fec_broadcasts_;
std::set<BroadcastHash> delivered_broadcasts_;
std::vector<adnl::AdnlNodeIdShort> neighbours_;
td::ListNode bcast_data_lru_;
td::ListNode bcast_fec_lru_;
std::queue<BroadcastHash> bcast_lru_;
@ -346,33 +404,6 @@ class OverlayImpl : public Overlay {
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) {
td::uint8 buf[64];
td::MutableSlice m{buf, 64};
@ -382,8 +413,7 @@ class OverlayImpl : public Overlay {
return td::sha256_bits256(td::Slice(buf, 64));
}
bool public_;
bool semi_public_ = false;
OverlayType overlay_type_;
OverlayPrivacyRules rules_;
td::string scope_;
bool announce_self_ = true;
@ -412,6 +442,25 @@ class OverlayImpl : public Overlay {
td::ListNode encryptor_lru_;
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

View file

@ -18,7 +18,9 @@
*/
#pragma once
#include "adnl/adnl-node-id.hpp"
#include "adnl/adnl.h"
#include "auto/tl/ton_api.h"
#include "dht/dht.h"
#include "td/actor/PromiseFuture.h"
@ -33,6 +35,8 @@ namespace ton {
namespace overlay {
enum class OverlayType { Public, FixedMemberList, CertificatedMembers };
class OverlayIdShort {
public:
OverlayIdShort() {
@ -88,6 +92,10 @@ struct CertificateFlags {
enum Values : td::uint32 { AllowFec = 1, Trusted = 2 };
};
struct OverlayMemberFlags {
enum Values : td::uint32 { DoNotReceiveBroadcasts = 1 };
};
enum BroadcastCheckResult { Forbidden = 1, NeedCheck = 2, Allowed = 3 };
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) {
auto it = authorized_keys_.find(hash);
if (it == authorized_keys_.end()) {
if (size > max_unath_size_) {
@ -158,9 +165,110 @@ class Certificate {
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 {
bool announce_self_ = true;
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 {
@ -175,6 +283,9 @@ class Overlays : public td::actor::Actor {
td::Promise<td::Unit> promise) {
promise.set_value(td::Unit());
}
virtual void get_stats_extra(td::Promise<std::string> promise) {
promise.set_result("");
}
virtual ~Callback() = default;
};
@ -192,6 +303,10 @@ class Overlays : public td::actor::Actor {
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,
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,
td::string scope) = 0;
virtual void create_public_overlay_ex(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope,
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,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback,
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 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,
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,
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 forget_peer(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay, adnl::AdnlNodeIdShort peer_id) = 0;
};
} // 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 {
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 {
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>
[[deprecated]] tl_object_ptr<T> clone_tl_object(const tl_object_ptr<T> &obj) {
auto B = serialize_tl_object(obj, true);

View file

@ -209,10 +209,15 @@ dht.query node:dht.node = True;
---types---
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.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.nodesV2 nodes:(vector overlay.NodeV2) = overlay.NodesV2;
overlay.messageExtra flags:# certificate:flags.0?overlay.MemberCertificate = overlay.MessageExtra;
overlay.message overlay:int256 = overlay.Message;
overlay.messageWithExtra overlay:int256 extra:overlay.messageExtra = overlay.Message;
//overlay.randomPeers peers:(vector adnl.node) = overlay.RandomPeers;
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.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.certificateV2 issued_by:PublicKey expire_at:int max_size:int flags:int signature:bytes = overlay.Certificate;
overlay.emptyCertificate = overlay.Certificate;
@ -242,13 +250,16 @@ overlay.broadcastNotFound = overlay.Broadcast;
---functions---
overlay.getRandomPeers peers:overlay.nodes = overlay.Nodes;
overlay.getRandomPeersV2 peers:overlay.NodesV2 = overlay.NodesV2;
overlay.query overlay:int256 = True;
overlay.queryWithExtra overlay:int256 extra:overlay.messageExtra = True;
overlay.getBroadcast hash:int256 = overlay.Broadcast;
overlay.getBroadcastList list:overlay.broadcastList = overlay.BroadcastList;
---types---
overlay.db.nodesV2 nodes:overlay.nodesV2 = overlay.db.Nodes;
overlay.db.nodes nodes:overlay.nodes = overlay.db.Nodes;
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.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.shardId workchain:int shard:long = tonNode.ShardId;
tonNode.blockDescriptionEmpty = 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.signatures block_id:tonNode.blockIdExt = 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.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.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.onePerfTimerStat time:int min:double avg:double max:double = engine.validator.OnePerfTimerStat;

Binary file not shown.

View file

@ -19,7 +19,8 @@
#pragma once
#include "ton-types.h"
#include "auto/tl/ton_api.h"
#include "auto/tl/ton_api.hpp"
#include "td/utils/overloaded.h"
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_};
}
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

View file

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

View file

@ -22,27 +22,15 @@
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) {
if (!compression_enabled) {
return serialize_tl_object(block, true);
}
vm::BagOfCells boc1, boc2;
TRY_STATUS(boc1.deserialize(block->data_));
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();
size_t decompressed_size;
TRY_RESULT(compressed, compress_candidate_data(block->data_, block->collated_data_, decompressed_size))
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,
@ -55,8 +43,34 @@ td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candi
if (f->decompressed_size_ > max_decompressed_data_size) {
return td::Status::Error("decompressed size is too big");
}
TRY_RESULT(decompressed, td::lz4_decompress(f->data_, f->decompressed_size_));
if (decompressed.size() != (size_t)f->decompressed_size_) {
TRY_RESULT(p, decompress_candidate_data(f->data_, 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");
}
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));
roots.erase(roots.begin());
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();
return create_tl_object<ton_api::validatorSession_candidate>(f->src_, f->round_, f->root_hash_, std::move(block_data),
std::move(collated_data));
return std::make_pair(std::move(block_data), std::move(collated_data));
}
} // namespace ton::validatorsession

View file

@ -20,10 +20,15 @@
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);
td::Result<tl_object_ptr<ton_api::validatorSession_candidate>> deserialize_candidate(td::Slice data,
bool compression_enabled,
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

View file

@ -72,6 +72,11 @@ td::uint32 ValidatorSessionDescriptionImpl::get_max_priority() const {
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(
td::uint32 src_idx, ValidatorSessionRootHash root_hash, ValidatorSessionFileHash file_hash,
ValidatorSessionCollatedDataFileHash collated_data_file_hash) const {

View file

@ -85,6 +85,7 @@ class ValidatorSessionDescription {
virtual ValidatorWeight get_total_weight() 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_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_attempt_seqno(td::uint64 t) 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::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 {
return static_cast<td::uint32>(ts >> 32);
}

View file

@ -21,6 +21,7 @@
#include "td/utils/crypto.h"
#include "candidate-serializer.h"
#include "td/utils/overloaded.h"
#include "ton/ton-tl.hpp"
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();
}
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 {
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_),
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) {
ref_ = fileref::BlockInfo{create_block_id(key.block_id_)};
}));

View file

@ -278,6 +278,38 @@ class Candidate {
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 {
public:
FileHash hash() const {
@ -316,7 +348,7 @@ class FileReferenceShort {
private:
td::Variant<fileref::Empty, fileref::BlockShort, fileref::ZeroStateShort, fileref::PersistentStateShort,
fileref::ProofShort, fileref::ProofShort, fileref::ProofLinkShort, fileref::SignaturesShort,
fileref::CandidateShort, fileref::BlockInfoShort>
fileref::CandidateShort, fileref::CandidateRefShort, fileref::BlockInfoShort>
ref_;
public:
@ -340,7 +372,8 @@ class FileReferenceShort {
class FileReference {
private:
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_;
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) {
auto source = PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}};
auto obj = create_serialize_tl_object<ton_api::db_candidate>(
PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}}.tl(), create_tl_block_id(candidate.id),
std::move(candidate.data), std::move(candidate.collated_data));
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_value(td::Unit());
}
source.tl(), create_tl_block_id(candidate.id), 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,
collated_file_hash = candidate.collated_file_hash](td::Result<td::Unit> R) mutable {
TRY_RESULT_PROMISE(promise, _, std::move(R));
td::actor::send_closure(archive_db, &ArchiveManager::add_temp_file_short, fileref::CandidateRef{block_id},
create_serialize_tl_object<ton_api::db_candidate_id>(
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,
fileref::Candidate{PublicKey{pubkeys::Ed25519{candidate.pubkey.as_bits256()}}, candidate.id,
candidate.collated_file_hash},
std::move(obj), std::move(P));
fileref::Candidate{source, candidate.id, candidate.collated_file_hash}, std::move(obj),
std::move(P));
}
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));
}
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,
td::Promise<td::Ref<ShardState>> promise) {
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 get_block_candidate(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
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,
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 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);
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);
void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<BlockHandle> promise);
void run_validate_query(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
void run_validate_query(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
BlockCandidate candidate, td::Ref<ValidatorSet> validator_set,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<ValidateCandidateResult> promise, bool is_fake = false);
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id,
std::vector<BlockIdExt> prev, Ed25519_PublicKey local_id, td::Ref<ValidatorSet> validator_set,
void run_collate_query(ShardIdFull shard, const BlockIdExt& min_masterchain_block_id, std::vector<BlockIdExt> prev,
Ed25519_PublicKey creator, td::Ref<ValidatorSet> validator_set,
td::Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<BlockCandidate> promise);
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
candidates-buffer.hpp
check-proof.hpp
collate-query-impl.h
collator-impl.h
collator.h
config.hpp

View file

@ -414,6 +414,35 @@ void AcceptBlockQuery::got_block_handle(BlockHandle handle) {
finish_query();
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()) {
td::actor::send_closure(
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_signatures();
void got_block_handle(BlockHandle handle);
void got_block_candidate_data(td::BufferSlice data);
void got_block_handle_cont();
void written_block_info();
void got_block_data(td::Ref<BlockData> data);
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 prev_key_block_exists_{false};
bool is_hardfork_{false};
UnixTime min_ts;
BlockIdExt min_mc_block_id;
std::vector<BlockIdExt> prev_blocks;
std::vector<Ref<ShardState>> prev_states;
@ -89,10 +88,9 @@ class Collator final : public td::actor::Actor {
static constexpr bool shard_splitting_enabled = true;
public:
Collator(ShardIdFull shard, bool is_hardfork, td::uint32 min_ts, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id,
Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<BlockCandidate> promise);
Collator(ShardIdFull shard, bool is_hardfork, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id, Ref<CollatorOptions> collator_opts,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout, td::Promise<BlockCandidate> promise);
~Collator() override = default;
bool is_busy() const {
return busy_;

View file

@ -66,7 +66,6 @@ static inline bool dbg(int c) {
*
* @param shard The shard of the new block.
* @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 prev A vector of BlockIdExt representing the previous blocks.
* @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 promise The promise to return the result.
*/
Collator::Collator(ShardIdFull shard, bool is_hardfork, UnixTime min_ts, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id,
Collator::Collator(ShardIdFull shard, bool is_hardfork, BlockIdExt min_masterchain_block_id,
std::vector<BlockIdExt> prev, td::Ref<ValidatorSet> validator_set, Ed25519_PublicKey collator_id,
Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<BlockCandidate> promise)
: shard_(shard)
, is_hardfork_(is_hardfork)
, min_ts(min_ts)
, min_mc_block_id{min_masterchain_block_id}
, prev_blocks(std::move(prev))
, created_by_(collator_id)

View file

@ -24,26 +24,7 @@
#include "vm/cells.h"
namespace ton {
using td::Ref;
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

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<BlockSignatureSet> approve_signatures, bool send_broadcast,
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),
std::move(signatures), std::move(approve_signatures), send_broadcast,
manager, std::move(promise))
td::actor::create_actor<AcceptBlockQuery>(PSTRING() << "accept" << id.id.to_str(), id, std::move(data), prev,
std::move(validator_set), std::move(signatures),
std::move(approve_signatures), send_broadcast, manager, std::move(promise))
.release();
}
@ -192,7 +192,7 @@ void run_check_proof_link_query(BlockIdExt id, td::Ref<ProofLink> proof, td::act
.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,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
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;
td::actor::create_actor<ValidateQuery>(PSTRING() << (is_fake ? "fakevalidate" : "validateblock") << shard.to_str()
<< ":" << (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),
is_fake)
.release();
}
void run_collate_query(ShardIdFull shard, td::uint32 min_ts, const BlockIdExt& min_masterchain_block_id,
std::vector<BlockIdExt> prev, Ed25519_PublicKey collator_id, td::Ref<ValidatorSet> validator_set,
void run_collate_query(ShardIdFull shard, const BlockIdExt& min_masterchain_block_id, std::vector<BlockIdExt> prev,
Ed25519_PublicKey creator, td::Ref<ValidatorSet> validator_set,
td::Ref<CollatorOptions> collator_opts, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<BlockCandidate> promise) {
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,
min_ts, min_masterchain_block_id, std::move(prev), std::move(validator_set),
collator_id, std::move(collator_opts), std::move(manager), timeout,
std::move(promise))
min_masterchain_block_id, std::move(prev), std::move(validator_set), creator,
std::move(collator_opts), std::move(manager), timeout, std::move(promise))
.release();
}
@ -237,7 +236,7 @@ void run_collate_hardfork(ShardIdFull shard, const BlockIdExt& min_masterchain_b
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>{},
Ed25519_PublicKey{Bits256::zero()}, td::Ref<CollatorOptions>{true},
std::move(manager), timeout, std::move(promise))

View file

@ -373,7 +373,8 @@ td::Status MasterchainStateQ::mc_init() {
td::Status MasterchainStateQ::mc_reinit() {
auto res = block::ConfigInfo::extract_config(
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();
next_validators_.reset();
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);
}
td::uint32 MasterchainStateQ::min_split_depth(WorkchainId workchain_id) const {
td::uint32 MasterchainStateQ::monitor_min_split_depth(WorkchainId workchain_id) const {
if (!config_) {
return 0;
}
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_) {
return 0;
}
@ -564,5 +565,9 @@ BlockIdExt MasterchainStateQ::prev_key_block_id(BlockSeqno seqno) const {
return block_id;
}
bool MasterchainStateQ::is_key_state() const {
return config_ ? config_->is_key_state() : false;
}
} // namespace validator
} // namespace ton

View file

@ -120,8 +120,8 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
bool has_workchain(WorkchainId workchain) const {
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 soft_min_split_depth(WorkchainId workchain_id) const override;
BlockSeqno min_ref_masterchain_seqno() const override;
td::Status prepare() override;
ZeroStateIdExt get_zerostate_id() const {
@ -137,6 +137,7 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
BlockIdExt last_key_block_id() const override;
BlockIdExt next_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;
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.
*
* @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 prev A vector of BlockIdExt representing the previous blocks.
* @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 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,
std::vector<BlockIdExt> prev, BlockCandidate candidate, Ref<ValidatorSet> validator_set,
ValidateQuery::ValidateQuery(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector<BlockIdExt> prev,
BlockCandidate candidate, Ref<ValidatorSet> validator_set,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<ValidateCandidateResult> promise, bool is_fake)
: shard_(shard)
, id_(candidate.id)
, min_ts(min_ts)
, min_mc_block_id(min_masterchain_block_id)
, prev_blocks(std::move(prev))
, 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) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "validateblock", duration);
}) {
proc_hash_.zero();
}
/**
@ -5033,12 +5030,10 @@ bool ValidateQuery::check_in_queue() {
neighbors_.at(kv->source).blk_.to_str());
}
if (unprocessed) {
inbound_queues_empty_ = false;
return true;
}
nb_out_msgs.next();
}
inbound_queues_empty_ = true;
return true;
}
@ -6919,6 +6914,7 @@ void ValidateQuery::written_candidate() {
void ValidateQuery::record_stats() {
double work_time = 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";
td::actor::send_closure(manager, &ValidatorManager::record_validate_query_stats, block_candidate.id, work_time,
cpu_work_time);

View file

@ -117,7 +117,7 @@ class ValidateQuery : public td::actor::Actor {
}
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,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,
td::Promise<ValidateCandidateResult> promise, bool is_fake = false);
@ -127,7 +127,6 @@ class ValidateQuery : public td::actor::Actor {
int pending{0};
const ShardIdFull shard_;
const BlockIdExt id_;
UnixTime min_ts;
BlockIdExt min_mc_block_id;
std::vector<BlockIdExt> prev_blocks;
std::vector<Ref<ShardState>> prev_states;
@ -224,8 +223,7 @@ class ValidateQuery : public td::actor::Actor {
td::RefInt256 import_fees_;
ton::LogicalTime proc_lt_{0}, claimed_proc_lt_{0}, min_enq_lt_{~0ULL};
ton::Bits256 proc_hash_, claimed_proc_hash_, min_enq_hash_;
bool inbound_queues_empty_{false};
ton::Bits256 proc_hash_ = ton::Bits256::zero(), claimed_proc_hash_, min_enq_hash_;
std::vector<std::tuple<Bits256, LogicalTime, LogicalTime>> msg_proc_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 get_block_candidate(ton::PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
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,
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 td::Ref<McShardHash> get_shard_from_config(ShardIdFull shard) 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 soft_min_split_depth(WorkchainId workchain_id) const = 0;
virtual BlockSeqno min_ref_masterchain_seqno() const = 0;
virtual bool ancestor_is_valid(BlockIdExt id) const = 0;
virtual ValidatorSessionConfig get_consensus_config() const = 0;
virtual BlockIdExt last_key_block_id() const = 0;
virtual BlockIdExt next_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,
ton::LogicalTime* end_lt = nullptr) 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()};
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));
}
@ -152,7 +152,7 @@ void ValidatorManagerImpl::validate_fake(BlockCandidate candidate, std::vector<B
}
});
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 */);
}
@ -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));
}
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) {
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_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
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_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;

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));
}
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) {
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_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
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_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;

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));
}
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) {
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);
if (it2 != next_validator_groups_.end()) {
if (!it2->second.actor.empty()) {
td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_,
last_masterchain_state_->get_unix_time());
td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_);
}
new_validator_groups_.emplace(val_group_id, std::move(it2->second));
} else {
auto G = create_validator_group(val_group_id, shard, val_set, key_seqno, opts, started_);
if (!G.empty()) {
td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_,
last_masterchain_state_->get_unix_time());
td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_);
}
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);
if (it2 != next_validator_groups_.end()) {
if (!it2->second.actor.empty()) {
td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_,
last_masterchain_state_->get_unix_time());
td::actor::send_closure(it2->second.actor, &ValidatorGroup::start, prev, last_masterchain_block_id_);
}
new_validator_groups_.emplace(val_group_id, std::move(it2->second));
} else {
auto G = create_validator_group(val_group_id, shard, val_set, key_seqno, opts, started_);
if (!G.empty()) {
td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_,
last_masterchain_state_->get_unix_time());
td::actor::send_closure(G, &ValidatorGroup::start, prev, last_masterchain_block_id_);
}
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_block_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
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_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;

View file

@ -202,10 +202,10 @@ void DownloadBlockNew::got_node_to_download(adnl::AdnlNodeIdShort node) {
}
if (client_.empty()) {
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_);
} 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)),
td::Timestamp::in(15.0), std::move(P));
}

View file

@ -250,7 +250,7 @@ void ShardClient::build_shard_overlays() {
for (auto &x : v) {
auto shard = x->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);
if (l > 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};
}));
run_collate_query(
shard_, min_ts_, min_masterchain_block_id_, prev_block_ids_,
Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}, validator_set_, opts_->get_collator_options(), manager_,
td::Timestamp::in(10.0), [SelfId = actor_id(this), cache = cached_collated_block_](td::Result<BlockCandidate> R) {
shard_, min_masterchain_block_id_, prev_block_ids_, Ed25519_PublicKey{local_id_full_.ed25519_value().raw()},
validator_set_, opts_->get_collator_options(), manager_, td::Timestamp::in(10.0),
[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));
});
}
@ -132,8 +132,8 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
}
VLOG(VALIDATOR_DEBUG) << "validating block candidate " << 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_,
manager_, td::Timestamp::in(15.0), std::move(P));
run_validate_query(shard_, min_masterchain_block_id_, prev_block_ids_, std::move(block), validator_set_, manager_,
td::Timestamp::in(15.0), std::move(P));
}
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;
min_masterchain_block_id_ = min_masterchain_block_id;
min_ts_ = min_ts;
cached_collated_block_ = nullptr;
approved_candidates_cache_.clear();
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;
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 destroy();
void start_up() override {
@ -114,7 +114,6 @@ class ValidatorGroup : public td::actor::Actor {
std::vector<BlockIdExt> prev_block_ids_;
BlockIdExt min_masterchain_block_id_;
UnixTime min_ts_;
td::Ref<ValidatorSet> validator_set_;
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);
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_;
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_candidate_from_db(PublicKey source, BlockIdExt id, FileHash collated_data_file_hash,
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_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;