1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-13 03:32:22 +00:00

Fast-sync overlays

* Semiprivate overlays
* Fast sync overlays in full-node
* Adjust shard overlays
This commit is contained in:
SpyCheese 2024-07-13 15:40:26 +03:00
parent ac3b8d6088
commit 3a8ef60bbb
38 changed files with 2545 additions and 964 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

@ -236,10 +236,6 @@ class HardforkCreator : public td::actor::Actor {
td::actor::send_closure(id_, &ton::validator::ValidatorManager::sync_complete,
td::PromiseCreator::lambda([](td::Unit) {}));
}
void update_shard_configuration(td::Ref<ton::validator::MasterchainState> state,
std::set<ton::ShardIdFull> shards_to_monitor,
std::set<ton::ShardIdFull> temporary_shards) override {
}
void send_ihr_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override {
}
void send_ext_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override {

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 {
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);
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,6 +29,7 @@
#include "td/db/RocksDb.h"
#include "td/utils/Status.h"
#include "td/utils/buffer.h"
#include "td/utils/overloaded.h"
#include "td/utils/port/Poll.h"
@ -41,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()) {
@ -57,19 +59,34 @@ 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) {
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);
F.ensure();
auto nodes = std::move(F.move_as_ok()->nodes_);
td::actor::send_closure(id, &Overlay::receive_nodes_from_db, std::move(nodes));
}
});
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);
F.ensure();
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());
db_.get(key, std::move(P));
}
@ -83,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);
}
}
@ -100,74 +121,113 @@ 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),
std::move(callback), std::move(rules), scope, std::move(opts)));
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)));
}
void OverlayManager::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) {
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();
return;
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()) {
VLOG(OVERLAY_WARNING) << this << ": can not parse overlay query [" << src << "->" << dst
<< "]: " << R.move_as_error();
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "bad overlay query header"));
return;
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
<< "]: " << 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,
@ -176,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) {
@ -217,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));
}
}
}
@ -234,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));
}
}
}
@ -245,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));
}
}
}
@ -256,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));
}
}
}
@ -274,7 +390,7 @@ void OverlayManager::get_overlay_random_peers(adnl::AdnlNodeIdShort local_id, Ov
promise.set_error(td::Status::Error(PSTRING() << "no such overlay " << overlay_id));
return;
}
td::actor::send_closure(it2->second, &Overlay::get_overlay_random_peers, max_peers, std::move(promise));
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,
@ -337,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());
@ -361,7 +477,7 @@ void OverlayManager::forget_peer(adnl::AdnlNodeIdShort local_id, OverlayIdShort
if (it2 == it->second.end()) {
return;
}
td::actor::send_closure(it2->second, &Overlay::forget_peer, peer_id);
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,
@ -470,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

@ -53,11 +53,19 @@ class OverlayManager : public Overlays {
void create_public_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules, td::string scope) override;
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;
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,7 +105,7 @@ 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;
@ -105,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,85 +16,159 @@
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);
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;
bool deleted = false;
for (auto &n : neighbours_) {
if (n == id) {
n = neighbours_[neighbours_.size() - 1];
neighbours_.resize(neighbours_.size() - 1);
deleted = true;
break;
}
}
CHECK(deleted);
P->set_neighbour(false);
del_from_neighbour_list(P);
}
peers_.remove(id);
bad_peers_.erase(id);
update_neighbours(0);
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;
auto &neighbours = peer_list_.neighbours_;
for (auto &n : neighbours) {
if (n == id) {
n = neighbours[neighbours.size() - 1];
neighbours.resize(neighbours.size() - 1);
deleted = true;
break;
}
}
CHECK(deleted);
P->set_neighbour(false);
}
void OverlayImpl::del_from_neighbour_list(const adnl::AdnlNodeIdShort &id) {
auto P = peer_list_.peers_.get(id);
CHECK(P != nullptr);
return del_from_neighbour_list(P);
}
void OverlayImpl::del_some_peers() {
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);
}
}
update_neighbours(0);
}
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;
@ -117,35 +191,82 @@ 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)) {
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);
} else {
bad_peers_.insert(peer);
if (!p->is_permanent_member()) {
if (p->is_alive()) {
peer_list_.bad_peers_.erase(peer);
} else {
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();
@ -158,16 +279,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;
}
add_peers(std::move(nodes));
auto R2 = fetch_tl_object<ton_api::overlay_nodesV2>(R.move_as_ok(), true);
if (R2.is_error()) {
VLOG(OVERLAY_WARNING) << this << ": dropping incorrect answer to overlay.getRandomPeers query from " << src << ": "
<< R2.move_as_error();
return;
}
add_peers(R2.move_as_ok());
}
void OverlayImpl::send_random_peers_cont(adnl::AdnlNodeIdShort src, OverlayNode node,
@ -177,10 +306,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;
}
@ -215,58 +347,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() - Overlays::overlay_peer_ttl()) {
if (X->is_neighbour()) {
bool found = false;
for (auto &n : neighbours_) {
if (n == X->get_id()) {
n = *neighbours_.rbegin();
found = true;
break;
}
}
CHECK(found);
neighbours_.pop_back();
X->set_neighbour(false);
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()) {
del_from_neighbour_list(X);
}
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();
@ -276,9 +460,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;
@ -292,18 +478,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()) {
@ -319,22 +506,221 @@ 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;
for (td::uint32 i = 0; i < max_size; i++) {
vec.push_back(
peer_list_.neighbours_[td::Random::fast(0, static_cast<td::int32>(peer_list_.neighbours_.size()) - 1)]);
}
return vec;
}
}
void OverlayImpl::send_message_to_neighbours(td::BufferSlice data) {
wait_neighbours_not_empty([this, data = std::move(data)](td::Result<td::Unit> R) {
if (R.is_error()) {
return;
}
for (auto &n : peer_list_.neighbours_) {
td::actor::send_closure(manager_, &OverlayManager::send_message, n, local_id_, overlay_id_, data.clone());
}
});
}
size_t OverlayImpl::neighbours_cnt() const {
return peer_list_.neighbours_.size();
}
void OverlayImpl::update_root_member_list(std::vector<adnl::AdnlNodeIdShort> ids,
std::vector<PublicKeyHash> root_public_keys, OverlayMemberCertificate cert) {
td::uint32 expectd_size =
(td::uint32)(ids.size() + root_public_keys.size() * opts_.max_slaves_in_semiprivate_overlay_);
if (expectd_size > opts_.max_peers_) {
opts_.max_peers_ = expectd_size;
}
if (expectd_size > opts_.max_neighbours_) {
opts_.max_neighbours_ = expectd_size;
}
std::sort(ids.begin(), ids.end());
auto old_root_public_keys = std::move(peer_list_.root_public_keys_);
for (const auto &pub_key : root_public_keys) {
auto it = old_root_public_keys.find(pub_key);
if (it != old_root_public_keys.end()) {
peer_list_.root_public_keys_.emplace(it->first, std::move(it->second));
} else {
peer_list_.root_public_keys_.emplace(pub_key, PeerList::SlaveKeys{});
}
}
std::vector<adnl::AdnlNodeIdShort> to_del;
peer_list_.peers_.iterate([&](const adnl::AdnlNodeIdShort &key, OverlayPeer &peer) {
peer.set_permanent(std::binary_search(ids.begin(), ids.end(), key));
if (peer.is_permanent_member()) {
peer.clear_certificate();
} else {
auto S = validate_peer_certificate(peer.get_id(), peer.certificate());
if (S.is_error()) {
to_del.push_back(peer.get_id());
}
}
});
for (const auto &id : to_del) {
del_peer(id);
}
for (const auto &id : ids) {
if (!peer_list_.peers_.exists(id)) {
OverlayNode node(id, overlay_id_, opts_.default_permanent_members_flags_);
OverlayPeer peer(std::move(node));
peer.set_permanent(true);
CHECK(peer.is_permanent_member());
peer_list_.peers_.insert(std::move(id), std::move(peer));
}
}
update_member_certificate(std::move(cert));
update_neighbours(0);
}
void OverlayImpl::update_member_certificate(OverlayMemberCertificate cert) {
peer_list_.cert_ = std::move(cert);
if (is_persistent_node(local_id_)) {
peer_list_.local_cert_is_valid_until_ = td::Timestamp::in(86400.0 * 365 * 100); /* 100 years */
} else {
auto R = validate_peer_certificate(local_id_, &peer_list_.cert_);
if (R.is_ok()) {
peer_list_.local_cert_is_valid_until_ = td::Timestamp::at_unix(cert.expire_at());
} else {
peer_list_.local_cert_is_valid_until_ = td::Timestamp::never();
}
}
}
bool OverlayImpl::has_valid_membership_certificate() {
if (overlay_type_ != OverlayType::CertificatedMembers) {
return true;
}
if (!peer_list_.local_cert_is_valid_until_) {
return false;
}
return !peer_list_.local_cert_is_valid_until_.is_in_past();
}
} // namespace overlay
} // namespace ton

View file

@ -27,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,
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) {
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);
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,
OverlayPrivacyRules rules, td::string scope, OverlayOptions opts) {
auto R = td::actor::create_actor<OverlayImpl>(
"overlay", keyring, adnl, manager, dht_node, local_id, std::move(overlay_id), OverlayType::Public,
std::vector<adnl::AdnlNodeIdShort>(), std::vector<PublicKeyHash>(), OverlayMemberCertificate{}, std::move(callback),
std::move(rules), std::move(scope), std::move(opts));
return td::actor::ActorOwn<Overlay>(std::move(R));
}
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)
@ -70,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";
@ -108,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_);
@ -135,17 +159,19 @@ void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getB
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "dropping get broadcast list query"));
}
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) {
VLOG(OVERLAY_WARNING) << this << ": received query in private overlay from unknown source " << src;
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "overlay is private"));
return;
}
} else {
on_ping_result(src, true);
/*void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, adnl::AdnlQueryId query_id, ton_api::overlay_customQuery &query) {
callback_->receive_query(src, query_id, id_, std::move(query.data_));
}
*/
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 not public"));
return;
}
auto R = fetch_tl_object<ton_api::Function>(data.clone(), true);
if (R.is_error()) {
@ -163,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));
}
@ -184,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 "
@ -198,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 "
@ -217,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;
return;
}
} else {
on_ping_result(src, true);
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;
}
auto X = fetch_tl_object<ton_api::overlay_Broadcast>(data.clone(), true);
if (X.is_error()) {
VLOG(OVERLAY_DEBUG) << this << ": received custom message";
@ -241,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);
@ -270,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) {
send_random_peers(P->get_id(), {});
if (overlay_type_ == OverlayType::Public) {
send_random_peers(P->get_id(), {});
} else {
send_random_peers_v2(P->get_id(), {});
}
}
} else {
VLOG(OVERLAY_WARNING) << "meber certificate ist invalid, valid_until="
<< peer_list_.local_cert_is_valid_until_.at_unix();
}
if (next_dht_query_ && next_dht_query_.is_in_past()) {
if (next_dht_query_ && next_dht_query_.is_in_past() && overlay_type_ == OverlayType::Public) {
next_dht_query_ = td::Timestamp::never();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<dht::DhtValue> res) {
td::actor::send_closure(SelfId, &OverlayImpl::receive_dht_nodes, std::move(res), true);
@ -285,21 +327,22 @@ void OverlayImpl::alarm() {
td::actor::send_closure(dht_node_, &dht::Dht::get_value, dht::DhtKey{overlay_id_.pubkey_hash(), "nodes", 0},
std::move(P));
}
if (update_db_at_.is_in_past()) {
if (peers_.size() > 0) {
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());
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_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);
@ -308,7 +351,7 @@ void OverlayImpl::alarm() {
}
void OverlayImpl::receive_dht_nodes(td::Result<dht::DhtValue> res, bool dummy) {
CHECK(public_);
CHECK(overlay_type_ == OverlayType::Public);
if (res.is_ok()) {
auto v = res.move_as_ok();
auto R = fetch_tl_object<ton_api::overlay_nodes>(v.value().clone(), true);
@ -354,7 +397,7 @@ void OverlayImpl::receive_dht_nodes(td::Result<dht::DhtValue> res, bool dummy) {
}
void OverlayImpl::update_dht_nodes(OverlayNode node) {
if (!public_) {
if (overlay_type_ != OverlayType::Public) {
return;
}
@ -412,7 +455,7 @@ void OverlayImpl::bcast_gc() {
}
void OverlayImpl::wait_neighbours_not_empty(td::Promise<td::Unit> promise, int max_retries) {
if (!neighbours_.empty()) {
if (!peer_list_.neighbours_.empty()) {
promise.set_result(td::Unit());
} else if (max_retries > 0) {
delay_action(
@ -425,18 +468,16 @@ void OverlayImpl::wait_neighbours_not_empty(td::Promise<td::Unit> promise, int m
}
}
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 : neighbours_) {
td::actor::send_closure(manager_, &OverlayManager::send_message, n, local_id_, overlay_id_, data.clone());
}
});
}
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;
@ -449,6 +490,15 @@ void OverlayImpl::send_broadcast(PublicKeyHash send_as, td::uint32 flags, td::Bu
}
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;
@ -472,6 +522,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) {
@ -479,7 +545,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;
}
@ -514,21 +580,23 @@ 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 {
if (R.is_error()) {
auto S = R.move_as_error();
LOG(ERROR) << oid << ": failed to get self node: " << S;
promise.set_error(std::move(S));
return;
}
auto V = R.move_as_ok();
s.update_signature(std::move(V.first));
s.update_adnl_id(adnl::AdnlNodeIdFull{V.second});
promise.set_value(std::move(s));
});
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;
promise.set_error(std::move(S));
return;
}
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));
});
td::actor::send_closure(keyring_, &keyring::Keyring::sign_add_get_public_key, local_id_.pubkey_hash(),
std::move(to_sign), std::move(P));
@ -620,17 +688,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);
@ -652,7 +709,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;
@ -673,7 +730,7 @@ void OverlayImpl::get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_
});
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()) {
@ -683,6 +740,14 @@ void OverlayImpl::get_stats(td::Promise<tl_object_ptr<ton_api::engine_validator_
});
}
bool OverlayImpl::has_valid_broadcast_certificate(const PublicKeyHash &source, size_t size, bool is_fec) {
if (size > std::numeric_limits<td::uint32>::max()) {
return false;
}
auto it = certs_.find(source);
return check_source_eligible(source, it == certs_.end() ? nullptr : it->second.get(), (td::uint32)size, is_fec);
}
} // namespace overlay
} // namespace ton

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,10 +70,14 @@ 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;

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(td::Result<dht::DhtValue> res, bool dummy);
void update_dht_nodes(OverlayNode node);
@ -187,6 +227,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);
@ -205,17 +247,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_;
}
@ -236,39 +268,53 @@ 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);
}
@ -283,6 +329,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,
@ -299,20 +347,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_;
@ -327,14 +383,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_;
@ -342,7 +395,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_;
@ -351,33 +403,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};
@ -387,8 +412,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;
@ -417,6 +441,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,107 @@ 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;
}
auto tl() const {
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 {
@ -208,11 +313,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;
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,
@ -246,6 +360,13 @@ 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;

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

@ -323,10 +323,6 @@ class TestNode : public td::actor::Actor {
td::actor::send_closure(id_, &ton::validator::ValidatorManager::sync_complete,
td::PromiseCreator::lambda([](td::Unit) {}));
}
void update_shard_configuration(td::Ref<ton::validator::MasterchainState> state,
std::set<ton::ShardIdFull> shards_to_monitor,
std::set<ton::ShardIdFull> temporary_shards) override {
}
void send_ihr_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override {
}
void send_ext_message(ton::AccountIdPrefixFull dst, td::BufferSlice data) override {

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;
@ -407,7 +418,7 @@ tonNode.shardPublicOverlayId workchain:int shard:long zero_state_file_hash:int25
tonNode.privateBlockOverlayId zero_state_file_hash:int256 nodes:(vector int256) = tonNode.PrivateBlockOverlayId;
tonNode.customOverlayId zero_state_file_hash:int256 name:string nodes:(vector int256) = tonNode.CustomOverlayId;
tonNode.privateBlockOverlayIdV2 zero_state_file_hash:int256 workchain:int shard:long nodes:(vector int256) senders:(vector int256) = tonNode.PrivateBlockOverlayIdV2;
tonNode.fastSyncOverlayId zero_state_file_hash:int256 shard:tonNode.shardId = tonNode.FastSyncOverlayId;
tonNode.keyBlocks blocks:(vector tonNode.blockIdExt) incomplete:Bool error:Bool = tonNode.KeyBlocks;
@ -614,7 +625,9 @@ engine.dht.config dht:(vector engine.dht) gc:engine.gc = engine.dht.Config;
engine.validator.fullNodeMaster port:int adnl:int256 = engine.validator.FullNodeMaster;
engine.validator.fullNodeSlave ip:int port:int adnl:PublicKey = engine.validator.FullNodeSlave;
engine.validator.fullNodeConfig ext_messages_broadcast_disabled:Bool = engine.validator.FullNodeConfig;
engine.validator.extraConfig state_serializer_enabled:Bool = engine.validator.ExtraConfig;
engine.validator.fastSyncMemberCertificate adnl_id:int256 certificate:overlay.MemberCertificate = engine.validator.FastSyncMemberCertificate;
engine.validator.extraConfig state_serializer_enabled:Bool fast_sync_member_certificates:(vector engine.validator.fastSyncMemberCertificate)
= engine.validator.ExtraConfig;
engine.validator.config out_port:int addrs:(vector engine.Addr) adnl:(vector engine.adnl)
dht:(vector engine.dht)
validators:(vector engine.validator) collators:(vector engine.collator)
@ -688,7 +701,8 @@ engine.validator.shardOverlayStats.neighbour id:string verison_major:int version
roundtrip:double unreliability:double has_state:string = engine.validator.shardOverlayStats.Neighbour;
engine.validator.shardOverlayStats shard:string mode:string
neighbours:(vector engine.validator.shardOverlayStats.neighbour) = engine.validator.ShardOverlayStats;
engine.validator.privateBlockOverlayV2Stats shard:string nodes:(vector int256) senders:(vector int256) created_at:int = engine.validator.PrivateBlockOverlayV2Stats;
engine.validator.fastSyncOverlayStats shard:string validators_adnl:(vector int256) root_public_keys:(vector int256)
member_certificate:overlay.MemberCertificate = engine.validator.FastSyncOverlayStats;
engine.validator.onePerfTimerStat time:int min:double avg:double max:double = engine.validator.OnePerfTimerStat;
engine.validator.perfTimerStatsByName name:string stats:(vector engine.validator.OnePerfTimerStat) = engine.validator.PerfTimerStatsByName;
@ -772,6 +786,9 @@ engine.validator.delShard shard:tonNode.shardId = engine.validator.Success;
engine.validator.setCollatorsList list:engine.validator.collatorsList = engine.validator.Success;
engine.validator.showCollatorsList = engine.validator.CollatorsList;
engine.validator.signOverlayMemberCertificate sign_by:int256 adnl_id:int256 slot:int expire_at:int = overlay.MemberCertificate;
engine.validator.importFastSyncMemberCertificate adnl_id:int256 certificate:overlay.MemberCertificate = engine.validator.Success;
---types---
storage.pong = storage.Pong;

Binary file not shown.

View file

@ -1432,3 +1432,51 @@ td::Status ShowCollatorsListQuery::receive(td::BufferSlice data) {
}
return td::Status::OK();
}
td::Status SignOverlayMemberCertificateQuery::run() {
TRY_RESULT_ASSIGN(key_hash_, tokenizer_.get_token<td::Bits256>());
TRY_RESULT_ASSIGN(adnl_id_, tokenizer_.get_token<td::Bits256>());
TRY_RESULT_ASSIGN(slot_, tokenizer_.get_token<int>());
TRY_RESULT_ASSIGN(expire_at_, tokenizer_.get_token<int>());
TRY_RESULT_ASSIGN(file_name_, tokenizer_.get_token<std::string>());
TRY_STATUS(tokenizer_.check_endl());
return td::Status::OK();
}
td::Status SignOverlayMemberCertificateQuery::send() {
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_signOverlayMemberCertificate>(
key_hash_, adnl_id_, slot_, expire_at_);
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
td::Status SignOverlayMemberCertificateQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::overlay_MemberCertificate>(data.as_slice(), true),
"received incorrect answer: ");
TRY_STATUS(td::write_file(file_name_, data));
td::TerminalIO::out() << "success\n";
return td::Status::OK();
}
td::Status ImportFastSyncMemberCertificateQuery::run() {
TRY_RESULT_ASSIGN(adnl_id_, tokenizer_.get_token<td::Bits256>());
TRY_RESULT_ASSIGN(file_name_, tokenizer_.get_token<std::string>());
TRY_STATUS(tokenizer_.check_endl());
return td::Status::OK();
}
td::Status ImportFastSyncMemberCertificateQuery::send() {
TRY_RESULT(data, td::read_file(file_name_));
TRY_RESULT(certificate, ton::fetch_tl_object<ton::ton_api::overlay_MemberCertificate>(data, true));
auto b = ton::create_serialize_tl_object<ton::ton_api::engine_validator_importFastSyncMemberCertificate>(
adnl_id_, std::move(certificate));
td::actor::send_closure(console_, &ValidatorEngineConsole::envelope_send_query, std::move(b), create_promise());
return td::Status::OK();
}
td::Status ImportFastSyncMemberCertificateQuery::receive(td::BufferSlice data) {
TRY_RESULT_PREFIX(f, ton::fetch_tl_object<ton::ton_api::engine_validator_success>(data.as_slice(), true),
"received incorrect answer: ");
td::TerminalIO::out() << "success\n";
return td::Status::OK();
}

View file

@ -1443,3 +1443,55 @@ class ShowCollatorsListQuery : public Query {
return get_name();
}
};
class SignOverlayMemberCertificateQuery : public Query {
public:
SignOverlayMemberCertificateQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
: Query(console, std::move(tokenizer)) {
}
td::Status run() override;
td::Status send() override;
td::Status receive(td::BufferSlice data) override;
static std::string get_name() {
return "signoverlaymembercertificate";
}
static std::string get_help() {
return "signoverlaymembercertificate <key_hash> <adnl_id> <slot> <expire_at> <filename>\tsign overlay member "
"certificate for <adnl_id> (hex) with <key_hash> (hex) in slot <slot>, valid until <expire_at>, "
"save to <filename>";
}
std::string name() const override {
return get_name();
}
private:
td::Bits256 key_hash_;
td::Bits256 adnl_id_;
int slot_;
ton::UnixTime expire_at_;
std::string file_name_;
};
class ImportFastSyncMemberCertificateQuery : public Query {
public:
ImportFastSyncMemberCertificateQuery(td::actor::ActorId<ValidatorEngineConsole> console, Tokenizer tokenizer)
: Query(console, std::move(tokenizer)) {
}
td::Status run() override;
td::Status send() override;
td::Status receive(td::BufferSlice data) override;
static std::string get_name() {
return "importfastsyncmembercertificate";
}
static std::string get_help() {
return "importfastsyncmembercertificate <adnl_id> <filename>\timport member certificate for fast sync overlay "
"for <adnl_id> (hex) from <filename>";
}
std::string name() const override {
return get_name();
}
private:
td::Bits256 adnl_id_;
std::string file_name_;
};

View file

@ -157,6 +157,8 @@ void ValidatorEngineConsole::run() {
add_query_runner(std::make_unique<QueryRunnerImpl<SetCollatorsListQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<ClearCollatorsListQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<ShowCollatorsListQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<SignOverlayMemberCertificateQuery>>());
add_query_runner(std::make_unique<QueryRunnerImpl<ImportFastSyncMemberCertificateQuery>>());
}
bool ValidatorEngineConsole::envelope_send_query(td::BufferSlice query, td::Promise<td::BufferSlice> promise) {

View file

@ -163,6 +163,13 @@ Config::Config(const ton::ton_api::engine_validator_config &config) {
}
if (config.extraconfig_) {
state_serializer_enabled = config.extraconfig_->state_serializer_enabled_;
for (auto &f : config.extraconfig_->fast_sync_member_certificates_) {
ton::adnl::AdnlNodeIdShort adnl_id{f->adnl_id_};
ton::overlay::OverlayMemberCertificate certificate{f->certificate_.get()};
if (!certificate.empty() && !certificate.is_expired()) {
fast_sync_member_certificates.emplace_back(adnl_id, std::move(certificate));
}
}
} else {
state_serializer_enabled = true;
}
@ -252,9 +259,15 @@ ton::tl_object_ptr<ton::ton_api::engine_validator_config> Config::tl() const {
}
ton::tl_object_ptr<ton::ton_api::engine_validator_extraConfig> extra_config_obj = {};
if (!state_serializer_enabled) {
if (!state_serializer_enabled || !fast_sync_member_certificates.empty()) {
// Non-default values
extra_config_obj = ton::create_tl_object<ton::ton_api::engine_validator_extraConfig>(state_serializer_enabled);
extra_config_obj = ton::create_tl_object<ton::ton_api::engine_validator_extraConfig>();
extra_config_obj->state_serializer_enabled_ = state_serializer_enabled;
for (const auto &[adnl_id, certificate] : fast_sync_member_certificates) {
extra_config_obj->fast_sync_member_certificates_.push_back(
ton::create_tl_object<ton::ton_api::engine_validator_fastSyncMemberCertificate>(adnl_id.bits256_value(),
certificate.tl()));
}
}
std::vector<ton::tl_object_ptr<ton::ton_api::engine_liteServer>> liteserver_vec;
@ -1995,6 +2008,10 @@ void ValidatorEngine::start_full_node() {
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::add_collator_adnl_id,
ton::adnl::AdnlNodeIdShort(c.adnl_id));
}
for (auto &x : config_.fast_sync_member_certificates) {
td::actor::send_closure(full_node_, &ton::validator::fullnode::FullNode::import_fast_sync_member_certificate,
x.first, x.second);
}
load_custom_overlays_config();
} else {
started_full_node();
@ -4140,6 +4157,95 @@ void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_delShard
});
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_signOverlayMemberCertificate &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
return;
}
if (!started_) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
return;
}
ton::PublicKeyHash public_key_hash{query.sign_by_};
ton::adnl::AdnlNodeIdShort adnl_id{query.adnl_id_};
int slot = query.slot_;
int expire_at = query.expire_at_;
td::actor::send_closure(
keyring_, &ton::keyring::Keyring::get_public_key, public_key_hash,
[=, promise = std::move(promise)](td::Result<ton::PublicKey> R) mutable {
if (R.is_error()) {
promise.set_value(create_control_query_error(R.move_as_error()));
return;
}
ton::overlay::OverlayMemberCertificate certificate{R.move_as_ok(), 0, slot, expire_at, td::BufferSlice{}};
if (certificate.is_expired()) {
promise.set_value(
create_control_query_error(td::Status::Error(ton::ErrorCode::error, "certificate is expired")));
return;
}
td::BufferSlice to_sign = certificate.to_sign_data(adnl_id);
td::actor::send_closure(keyring_, &ton::keyring::Keyring::sign_message, public_key_hash, std::move(to_sign),
[certificate = std::move(certificate),
promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_value(create_control_query_error(R.move_as_error()));
return;
}
certificate.set_signature(R.move_as_ok());
promise.set_value(ton::serialize_tl_object(certificate.tl(), true));
});
});
}
void ValidatorEngine::run_control_query(ton::ton_api::engine_validator_importFastSyncMemberCertificate &query,
td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {
if (!(perm & ValidatorEnginePermissions::vep_modify)) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "not authorized")));
return;
}
if (!started_) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::notready, "not started")));
return;
}
ton::adnl::AdnlNodeIdShort adnl_id{query.adnl_id_};
ton::overlay::OverlayMemberCertificate certificate{query.certificate_.get()};
if (certificate.empty()) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "certificate is empty")));
return;
}
td::Status S = certificate.check_signature(adnl_id);
if (S.is_error()) {
promise.set_value(create_control_query_error(std::move(S)));
return;
}
for (auto &old_cert : config_.fast_sync_member_certificates) {
if (old_cert.first == adnl_id && old_cert.second.issued_by() == certificate.issued_by() &&
old_cert.second.expire_at() == certificate.expire_at() && old_cert.second.slot() == certificate.slot()) {
promise.set_value(create_control_query_error(td::Status::Error(ton::ErrorCode::error, "duplicate certificate")));
return;
}
}
config_.fast_sync_member_certificates.emplace_back(adnl_id, certificate);
write_config([=, promise = std::move(promise), full_node = full_node_.get()](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
promise.set_value(create_control_query_error(R.move_as_error()));
} else {
if (!full_node.empty()) {
td::actor::send_closure(full_node, &ton::validator::fullnode::FullNode::import_fast_sync_member_certificate,
adnl_id, std::move(certificate));
}
promise.set_value(
ton::serialize_tl_object(ton::create_tl_object<ton::ton_api::engine_validator_success>(), true));
}
});
}
void ValidatorEngine::process_control_query(td::uint16 port, ton::adnl::AdnlNodeIdShort src,
ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {

View file

@ -101,6 +101,8 @@ struct Config {
std::vector<ton::ShardIdFull> shards_to_monitor;
bool state_serializer_enabled = true;
std::vector<std::pair<ton::adnl::AdnlNodeIdShort, ton::overlay::OverlayMemberCertificate>>
fast_sync_member_certificates;
void decref(ton::PublicKeyHash key);
void incref(ton::PublicKeyHash key) {
@ -524,6 +526,10 @@ class ValidatorEngine : public td::actor::Actor {
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_showCollatorsList &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_signOverlayMemberCertificate &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
void run_control_query(ton::ton_api::engine_validator_importFastSyncMemberCertificate &query, td::BufferSlice data,
ton::PublicKeyHash src, td::uint32 perm, td::Promise<td::BufferSlice> promise);
template <class T>
void run_control_query(T &query, td::BufferSlice data, ton::PublicKeyHash src, td::uint32 perm,
td::Promise<td::BufferSlice> promise) {

View file

@ -153,8 +153,8 @@ set(FULL_NODE_SOURCE
full-node-private-overlay.cpp
full-node-serializer.hpp
full-node-serializer.cpp
full-node-private-overlay-v2.hpp
full-node-private-overlay-v2.cpp
full-node-fast-sync-overlays.hpp
full-node-fast-sync-overlays.cpp
net/download-block.hpp
net/download-block.cpp

View file

@ -0,0 +1,416 @@
/*
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/>.
*/
#include "full-node-fast-sync-overlays.hpp"
#include "checksum.h"
#include "ton/ton-tl.hpp"
#include "common/delay.h"
#include "td/utils/JsonBuilder.h"
#include "tl/tl_json.h"
#include "auto/tl/ton_api_json.h"
#include "full-node-serializer.hpp"
namespace ton::validator::fullnode {
void FullNodeFastSyncOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query) {
process_block_broadcast(src, query);
}
void FullNodeFastSyncOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query) {
process_block_broadcast(src, query);
}
void FullNodeFastSyncOverlay::process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
auto B = deserialize_block_broadcast(query, overlay::Overlays::max_fec_broadcast_size());
if (B.is_error()) {
LOG(DEBUG) << "dropped broadcast: " << B.move_as_error();
return;
}
VLOG(FULL_NODE_DEBUG) << "Received block broadcast in fast sync overlay from " << src << ": "
<< B.ok().block_id.to_str();
td::actor::send_closure(full_node_, &FullNode::process_block_broadcast, B.move_as_ok());
}
void FullNodeFastSyncOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query) {
BlockIdExt block_id = create_block_id(query.block_->block_);
VLOG(FULL_NODE_DEBUG) << "Received newShardBlockBroadcast in fast sync overlay from " << src << ": "
<< block_id.to_str();
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_shard_block, block_id,
query.block_->cc_seqno_, std::move(query.block_->data_));
}
void FullNodeFastSyncOverlay::process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcast &query) {
process_block_candidate_broadcast(src, query);
}
void FullNodeFastSyncOverlay::process_broadcast(PublicKeyHash src,
ton_api::tonNode_newBlockCandidateBroadcastCompressed &query) {
process_block_candidate_broadcast(src, query);
}
void FullNodeFastSyncOverlay::process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
BlockIdExt block_id;
CatchainSeqno cc_seqno;
td::uint32 validator_set_hash;
td::BufferSlice data;
auto S = deserialize_block_candidate_broadcast(query, block_id, cc_seqno, validator_set_hash, data,
overlay::Overlays::max_fec_broadcast_size());
if (S.is_error()) {
LOG(DEBUG) << "dropped broadcast: " << S;
return;
}
if (data.size() > FullNode::max_block_size()) {
VLOG(FULL_NODE_WARNING) << "received block candidate with too big size from " << src;
return;
}
if (td::sha256_bits256(data.as_slice()) != block_id.file_hash) {
VLOG(FULL_NODE_WARNING) << "received block candidate with incorrect file hash from " << src;
return;
}
VLOG(FULL_NODE_DEBUG) << "Received newBlockCandidate in fast sync overlay from " << src << ": " << block_id.to_str();
td::actor::send_closure(full_node_, &FullNode::process_block_candidate_broadcast, block_id, cc_seqno,
validator_set_hash, std::move(data));
}
void FullNodeFastSyncOverlay::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
auto B = fetch_tl_object<ton_api::tonNode_Broadcast>(std::move(broadcast), true);
if (B.is_error()) {
return;
}
ton_api::downcast_call(*B.move_as_ok(), [src, Self = this](auto &obj) { Self->process_broadcast(src, obj); });
}
void FullNodeFastSyncOverlay::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
if (!inited_) {
return;
}
VLOG(FULL_NODE_DEBUG) << "Sending newShardBlockBroadcast in fast sync overlay: " << block_id.to_str();
auto B = create_serialize_tl_object<ton_api::tonNode_newShardBlockBroadcast>(
create_tl_object<ton_api::tonNode_newShardBlock>(create_tl_block_id(block_id), cc_seqno, std::move(data)));
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_ex, local_id_, overlay_id_,
local_id_.pubkey_hash(), 0, std::move(B));
} else {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), std::move(B));
}
}
void FullNodeFastSyncOverlay::send_broadcast(BlockBroadcast broadcast) {
if (!inited_) {
return;
}
VLOG(FULL_NODE_DEBUG) << "Sending block broadcast in fast sync overlay (with compression): "
<< broadcast.block_id.to_str();
auto B = serialize_block_broadcast(broadcast, true); // compression_enabled = true
if (B.is_error()) {
VLOG(FULL_NODE_WARNING) << "failed to serialize block broadcast: " << B.move_as_error();
return;
}
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
}
void FullNodeFastSyncOverlay::send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno,
td::uint32 validator_set_hash, td::BufferSlice data) {
if (!inited_) {
return;
}
auto B =
serialize_block_candidate_broadcast(block_id, cc_seqno, validator_set_hash, data, true); // compression enabled
if (B.is_error()) {
VLOG(FULL_NODE_WARNING) << "failed to serialize block candidate broadcast: " << B.move_as_error();
return;
}
VLOG(FULL_NODE_DEBUG) << "Sending newBlockCandidate in fast sync overlay (with compression): " << block_id.to_str();
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
}
void FullNodeFastSyncOverlay::start_up() {
auto X = create_hash_tl_object<ton_api::tonNode_fastSyncOverlayId>(zero_state_file_hash_, create_tl_shard_id(shard_));
td::BufferSlice b{32};
b.as_slice().copy_from(as_slice(X));
overlay_id_full_ = overlay::OverlayIdFull{std::move(b)};
overlay_id_ = overlay_id_full_.compute_short_id();
try_init();
}
void FullNodeFastSyncOverlay::try_init() {
// Sometimes adnl id is added to validator engine later (or not at all)
td::actor::send_closure(
adnl_, &adnl::Adnl::check_id_exists, local_id_, [SelfId = actor_id(this)](td::Result<bool> R) {
if (R.is_ok() && R.ok()) {
td::actor::send_closure(SelfId, &FullNodeFastSyncOverlay::init);
} else {
delay_action([SelfId]() { td::actor::send_closure(SelfId, &FullNodeFastSyncOverlay::try_init); },
td::Timestamp::in(30.0));
}
});
}
void FullNodeFastSyncOverlay::init() {
LOG(INFO) << "Creating fast sync overlay for shard " << shard_.to_str() << ", adnl_id=" << local_id_;
class Callback : public overlay::Overlays::Callback {
public:
void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
}
void receive_query(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
}
void receive_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
td::actor::send_closure(node_, &FullNodeFastSyncOverlay::receive_broadcast, src, std::move(data));
}
void check_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
td::Promise<td::Unit> promise) override {
}
void get_stats_extra(td::Promise<std::string> promise) override {
td::actor::send_closure(node_, &FullNodeFastSyncOverlay::get_stats_extra, std::move(promise));
}
explicit Callback(td::actor::ActorId<FullNodeFastSyncOverlay> node) : node_(node) {
}
private:
td::actor::ActorId<FullNodeFastSyncOverlay> node_;
};
overlay::OverlayPrivacyRules rules{overlay::Overlays::max_fec_broadcast_size(),
overlay::CertificateFlags::AllowFec | overlay::CertificateFlags::Trusted,
{}};
std::string scope = PSTRING() << R"({ "type": "fast-sync", "shard_id": )" << shard_.shard
<< ", \"workchain_id\": " << shard_.workchain << " }";
overlay::OverlayOptions options;
bool is_validator = std::find(current_validators_adnl_.begin(), current_validators_adnl_.end(), local_id_) !=
current_validators_adnl_.end();
if (!shard_.is_masterchain()) {
options.default_permanent_members_flags_ = overlay::OverlayMemberFlags::DoNotReceiveBroadcasts;
options.local_overlay_member_flags_ = is_validator ? overlay::OverlayMemberFlags::DoNotReceiveBroadcasts : 0;
}
options.max_slaves_in_semiprivate_overlay_ = 100000; // TODO: set lower limit (high limit for testing)
td::actor::send_closure(overlays_, &overlay::Overlays::create_semiprivate_overlay, local_id_,
overlay_id_full_.clone(), current_validators_adnl_, root_public_keys_, member_certificate_,
std::make_unique<Callback>(actor_id(this)), rules, std::move(scope), options);
inited_ = true;
}
void FullNodeFastSyncOverlay::tear_down() {
if (inited_) {
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, local_id_, overlay_id_);
}
}
void FullNodeFastSyncOverlay::set_validators(std::vector<PublicKeyHash> root_public_keys,
std::vector<adnl::AdnlNodeIdShort> current_validators_adnl) {
root_public_keys_ = std::move(root_public_keys);
current_validators_adnl_ = std::move(current_validators_adnl);
if (inited_) {
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, local_id_, overlay_id_);
init();
}
}
void FullNodeFastSyncOverlay::set_member_certificate(overlay::OverlayMemberCertificate member_certificate) {
member_certificate_ = std::move(member_certificate);
if (inited_) {
td::actor::send_closure(overlays_, &overlay::Overlays::update_member_certificate, local_id_, overlay_id_,
member_certificate_);
}
}
void FullNodeFastSyncOverlay::get_stats_extra(td::Promise<std::string> promise) {
auto res = create_tl_object<ton_api::engine_validator_fastSyncOverlayStats>();
res->shard_ = shard_.to_str();
for (const auto &x : current_validators_adnl_) {
res->validators_adnl_.push_back(x.bits256_value());
}
for (const auto &x : root_public_keys_) {
res->root_public_keys_.push_back(x.bits256_value());
}
res->member_certificate_ = member_certificate_.tl();
promise.set_result(td::json_encode<std::string>(td::ToJson(*res), true));
}
td::actor::ActorId<FullNodeFastSyncOverlay> FullNodeFastSyncOverlays::choose_overlay(ShardIdFull shard) {
for (auto &p : id_to_overlays_) {
auto &overlays = p.second.overlays_;
ShardIdFull cur_shard = shard;
while (true) {
auto it = overlays.find(cur_shard);
if (it != overlays.end()) {
return it->second.get();
}
if (cur_shard.pfx_len() == 0) {
break;
}
cur_shard = shard_parent(cur_shard);
}
}
return {};
}
void FullNodeFastSyncOverlays::update_overlays(td::Ref<MasterchainState> state,
std::set<adnl::AdnlNodeIdShort> my_adnl_ids,
std::set<ShardIdFull> monitoring_shards,
const FileHash &zero_state_file_hash,
const td::actor::ActorId<keyring::Keyring> &keyring,
const td::actor::ActorId<adnl::Adnl> &adnl,
const td::actor::ActorId<overlay::Overlays> &overlays,
const td::actor::ActorId<ValidatorManagerInterface> &validator_manager,
const td::actor::ActorId<FullNode> &full_node) {
monitoring_shards.insert(ShardIdFull{masterchainId});
std::set<ShardIdFull> all_shards;
all_shards.insert(ShardIdFull{masterchainId});
td::uint32 monitor_min_split = state->monitor_min_split_depth(basechainId);
for (td::uint64 i = 0; i < (1ULL << monitor_min_split); ++i) {
all_shards.insert(ShardIdFull{basechainId, (i * 2 + 1) << (63 - monitor_min_split)});
}
// Remove overlays for removed adnl ids and shards
for (auto it = id_to_overlays_.begin(); it != id_to_overlays_.end();) {
if (my_adnl_ids.count(it->first)) {
auto &overlays_info = it->second;
;
auto &current_shards = overlays_info.is_validator_ ? all_shards : monitoring_shards;
for (auto it2 = overlays_info.overlays_.begin(); it2 != overlays_info.overlays_.end();) {
if (current_shards.count(it2->first)) {
++it2;
} else {
it2 = overlays_info.overlays_.erase(it2);
}
}
++it;
} else {
it = id_to_overlays_.erase(it);
}
}
// On new keyblock - update validator set
bool updated_validators = false;
if (!last_key_block_seqno_ || last_key_block_seqno_.value() != state->last_key_block_id().seqno()) {
updated_validators = true;
last_key_block_seqno_ = state->last_key_block_id().seqno();
root_public_keys_.clear();
current_validators_adnl_.clear();
// Previous, current and next validator sets
for (int i = -1; i <= 1; ++i) {
auto val_set = state->get_total_validator_set(i);
if (val_set.is_null()) {
continue;
}
for (const ValidatorDescr &val : val_set->export_vector()) {
PublicKeyHash public_key_hash = ValidatorFullId{val.key}.compute_short_id();
root_public_keys_.push_back(public_key_hash);
if (i == 0) {
current_validators_adnl_.emplace_back(val.addr.is_zero() ? public_key_hash.bits256_value() : val.addr);
}
}
}
std::sort(root_public_keys_.begin(), root_public_keys_.end());
root_public_keys_.erase(std::unique(root_public_keys_.begin(), root_public_keys_.end()), root_public_keys_.end());
std::sort(current_validators_adnl_.begin(), current_validators_adnl_.end());
for (auto &[local_id, overlays_info] : id_to_overlays_) {
overlays_info.is_validator_ =
std::binary_search(current_validators_adnl_.begin(), current_validators_adnl_.end(), local_id);
for (auto &[_, overlay] : overlays_info.overlays_) {
td::actor::send_closure(overlay, &FullNodeFastSyncOverlay::set_validators, root_public_keys_,
current_validators_adnl_);
}
}
}
// Cleanup outdated certificates
double now = td::Clocks::system();
for (auto &[_, certificates] : member_certificates_) {
certificates.erase(std::remove_if(certificates.begin(), certificates.end(),
[&](const overlay::OverlayMemberCertificate &certificate) {
return certificate.is_expired(now);
}),
certificates.end());
}
for (adnl::AdnlNodeIdShort local_id : my_adnl_ids) {
bool is_new = !id_to_overlays_.count(local_id);
auto &overlays_info = id_to_overlays_[local_id];
// Update is_validator and current_certificate
if (is_new) {
overlays_info.is_validator_ =
std::binary_search(current_validators_adnl_.begin(), current_validators_adnl_.end(), local_id);
}
bool changed_certificate = false;
// Check if certificate is outdated or no longer authorized by current root keys
if (!overlays_info.current_certificate_.empty() && overlays_info.current_certificate_.is_expired(now)) {
changed_certificate = true;
overlays_info.current_certificate_ = {};
}
if (!overlays_info.current_certificate_.empty() && updated_validators &&
!std::binary_search(root_public_keys_.begin(), root_public_keys_.end(),
overlays_info.current_certificate_.issued_by().compute_short_id())) {
changed_certificate = true;
overlays_info.current_certificate_ = {};
}
if (overlays_info.current_certificate_.empty()) {
auto it = member_certificates_.find(local_id);
if (it != member_certificates_.end()) {
for (const overlay::OverlayMemberCertificate &certificate : it->second) {
if (std::binary_search(root_public_keys_.begin(), root_public_keys_.end(),
certificate.issued_by().compute_short_id())) {
changed_certificate = true;
overlays_info.current_certificate_ = it->second.front();
break;
}
}
}
}
// Remove if it is not authorized
if (!overlays_info.is_validator_ && overlays_info.current_certificate_.empty()) {
id_to_overlays_.erase(local_id);
continue;
}
// Update shard overlays
auto &current_shards = overlays_info.is_validator_ ? all_shards : monitoring_shards;
for (ShardIdFull shard_id : current_shards) {
auto &overlay = overlays_info.overlays_[shard_id];
if (overlay.empty()) {
overlay = td::actor::create_actor<FullNodeFastSyncOverlay>(
PSTRING() << "FastSyncOv" << shard_id.to_str(), local_id, shard_id, zero_state_file_hash,
root_public_keys_, current_validators_adnl_, overlays_info.current_certificate_, keyring, adnl, overlays,
validator_manager, full_node);
} else if (changed_certificate) {
td::actor::send_closure(overlay, &FullNodeFastSyncOverlay::set_member_certificate,
overlays_info.current_certificate_);
}
}
}
}
void FullNodeFastSyncOverlays::add_member_certificate(adnl::AdnlNodeIdShort local_id,
overlay::OverlayMemberCertificate member_certificate) {
if (member_certificate.empty() || member_certificate.is_expired()) {
return;
}
member_certificates_[local_id].push_back(std::move(member_certificate));
// Overlays will be updated in the next update_overlays
}
} // namespace ton::validator::fullnode

View file

@ -20,7 +20,7 @@
namespace ton::validator::fullnode {
class FullNodePrivateOverlayV2 : public td::actor::Actor {
class FullNodeFastSyncOverlay : public td::actor::Actor {
public:
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast& query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed& query);
@ -28,9 +28,9 @@ class FullNodePrivateOverlayV2 : public td::actor::Actor {
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast& query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcast &query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcastCompressed &query);
void process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcast& query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_newBlockCandidateBroadcastCompressed& query);
void process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast& query);
template <class T>
void process_broadcast(PublicKeyHash, T&) {
@ -46,26 +46,26 @@ class FullNodePrivateOverlayV2 : public td::actor::Actor {
void start_up() override;
void tear_down() override;
void destroy() {
stop();
}
void set_validators(std::vector<PublicKeyHash> root_public_keys,
std::vector<adnl::AdnlNodeIdShort> current_validators_adnl);
void set_member_certificate(overlay::OverlayMemberCertificate member_certificate);
FullNodePrivateOverlayV2(adnl::AdnlNodeIdShort local_id, ShardIdFull shard, std::vector<adnl::AdnlNodeIdShort> nodes,
std::vector<adnl::AdnlNodeIdShort> senders, FileHash zero_state_file_hash,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<FullNode> full_node)
FullNodeFastSyncOverlay(adnl::AdnlNodeIdShort local_id, ShardIdFull shard, FileHash zero_state_file_hash,
std::vector<PublicKeyHash> root_public_keys,
std::vector<adnl::AdnlNodeIdShort> current_validators_adnl,
overlay::OverlayMemberCertificate member_certificate,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<FullNode> full_node)
: local_id_(local_id)
, shard_(shard)
, nodes_(std::move(nodes))
, senders_(std::move(senders))
, root_public_keys_(std::move(root_public_keys))
, current_validators_adnl_(std::move(current_validators_adnl))
, member_certificate_(std::move(member_certificate))
, zero_state_file_hash_(zero_state_file_hash)
, keyring_(keyring)
, adnl_(adnl)
, rldp_(rldp)
, rldp2_(rldp2)
, overlays_(overlays)
, validator_manager_(validator_manager)
, full_node_(full_node) {
@ -74,14 +74,13 @@ class FullNodePrivateOverlayV2 : public td::actor::Actor {
private:
adnl::AdnlNodeIdShort local_id_;
ShardIdFull shard_;
std::vector<adnl::AdnlNodeIdShort> nodes_;
std::vector<adnl::AdnlNodeIdShort> senders_;
std::vector<PublicKeyHash> root_public_keys_;
std::vector<adnl::AdnlNodeIdShort> current_validators_adnl_;
overlay::OverlayMemberCertificate member_certificate_;
FileHash zero_state_file_hash_;
td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<adnl::Adnl> adnl_;
td::actor::ActorId<rldp::Rldp> rldp_;
td::actor::ActorId<rldp2::Rldp> rldp2_;
td::actor::ActorId<overlay::Overlays> overlays_;
td::actor::ActorId<ValidatorManagerInterface> validator_manager_;
td::actor::ActorId<FullNode> full_node_;
@ -96,29 +95,30 @@ class FullNodePrivateOverlayV2 : public td::actor::Actor {
void get_stats_extra(td::Promise<std::string> promise);
};
class FullNodePrivateBlockOverlaysV2 {
class FullNodeFastSyncOverlays {
public:
td::actor::ActorId<FullNodePrivateOverlayV2> choose_overlay(ShardIdFull shard);
td::actor::ActorId<FullNodeFastSyncOverlay> choose_overlay(ShardIdFull shard);
void update_overlays(td::Ref<MasterchainState> state, std::set<adnl::AdnlNodeIdShort> my_adnl_ids,
const FileHash& zero_state_file_hash, const td::actor::ActorId<keyring::Keyring>& keyring,
const td::actor::ActorId<adnl::Adnl>& adnl, const td::actor::ActorId<rldp::Rldp>& rldp,
const td::actor::ActorId<rldp2::Rldp>& rldp2,
std::set<ShardIdFull> monitoring_shards, const FileHash& zero_state_file_hash,
const td::actor::ActorId<keyring::Keyring>& keyring, const td::actor::ActorId<adnl::Adnl>& adnl,
const td::actor::ActorId<overlay::Overlays>& overlays,
const td::actor::ActorId<ValidatorManagerInterface>& validator_manager,
const td::actor::ActorId<FullNode>& full_node);
void destroy_overlays();
void add_member_certificate(adnl::AdnlNodeIdShort local_id, overlay::OverlayMemberCertificate member_certificate);
private:
struct Overlays {
struct ShardOverlay {
td::actor::ActorOwn<FullNodePrivateOverlayV2> overlay_;
std::vector<adnl::AdnlNodeIdShort> nodes_, senders_;
bool is_sender_ = false;
};
std::map<ShardIdFull, ShardOverlay> overlays_;
std::map<ShardIdFull, td::actor::ActorOwn<FullNodeFastSyncOverlay>> overlays_;
overlay::OverlayMemberCertificate current_certificate_;
bool is_validator_{false};
};
std::map<adnl::AdnlNodeIdShort, Overlays> id_to_overlays_; // local_id -> overlays
std::map<adnl::AdnlNodeIdShort, std::vector<overlay::OverlayMemberCertificate>> member_certificates_;
td::optional<BlockSeqno> last_key_block_seqno_;
std::vector<PublicKeyHash> root_public_keys_;
std::vector<adnl::AdnlNodeIdShort> current_validators_adnl_;
};
} // namespace ton::validator::fullnode

View file

@ -1,384 +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/>.
*/
#include "full-node-private-overlay-v2.hpp"
#include "checksum.h"
#include "ton/ton-tl.hpp"
#include "common/delay.h"
#include "td/utils/JsonBuilder.h"
#include "tl/tl_json.h"
#include "auto/tl/ton_api_json.h"
#include "full-node-serializer.hpp"
namespace ton::validator::fullnode {
void FullNodePrivateOverlayV2::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query) {
process_block_broadcast(src, query);
}
void FullNodePrivateOverlayV2::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query) {
process_block_broadcast(src, query);
}
void FullNodePrivateOverlayV2::process_block_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
auto B = deserialize_block_broadcast(query, overlay::Overlays::max_fec_broadcast_size());
if (B.is_error()) {
LOG(DEBUG) << "dropped broadcast: " << B.move_as_error();
return;
}
VLOG(FULL_NODE_DEBUG) << "Received block broadcast in private overlay from " << src << ": "
<< B.ok().block_id.to_str();
td::actor::send_closure(full_node_, &FullNode::process_block_broadcast, B.move_as_ok());
}
void FullNodePrivateOverlayV2::process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query) {
BlockIdExt block_id = create_block_id(query.block_->block_);
VLOG(FULL_NODE_DEBUG) << "Received newShardBlockBroadcast in private overlay from " << src << ": "
<< block_id.to_str();
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_shard_block, block_id,
query.block_->cc_seqno_, std::move(query.block_->data_));
}
void FullNodePrivateOverlayV2::process_broadcast(PublicKeyHash src,
ton_api::tonNode_newBlockCandidateBroadcast &query) {
process_block_candidate_broadcast(src, query);
}
void FullNodePrivateOverlayV2::process_broadcast(PublicKeyHash src,
ton_api::tonNode_newBlockCandidateBroadcastCompressed &query) {
process_block_candidate_broadcast(src, query);
}
void FullNodePrivateOverlayV2::process_block_candidate_broadcast(PublicKeyHash src, ton_api::tonNode_Broadcast &query) {
BlockIdExt block_id;
CatchainSeqno cc_seqno;
td::uint32 validator_set_hash;
td::BufferSlice data;
auto S = deserialize_block_candidate_broadcast(query, block_id, cc_seqno, validator_set_hash, data,
overlay::Overlays::max_fec_broadcast_size());
if (S.is_error()) {
LOG(DEBUG) << "dropped broadcast: " << S;
return;
}
if (data.size() > FullNode::max_block_size()) {
VLOG(FULL_NODE_WARNING) << "received block candidate with too big size from " << src;
return;
}
if (td::sha256_bits256(data.as_slice()) != block_id.file_hash) {
VLOG(FULL_NODE_WARNING) << "received block candidate with incorrect file hash from " << src;
return;
}
VLOG(FULL_NODE_DEBUG) << "Received newBlockCandidate in private overlay from " << src << ": " << block_id.to_str();
td::actor::send_closure(full_node_, &FullNode::process_block_candidate_broadcast, block_id, cc_seqno,
validator_set_hash, std::move(data));
}
void FullNodePrivateOverlayV2::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
auto B = fetch_tl_object<ton_api::tonNode_Broadcast>(std::move(broadcast), true);
if (B.is_error()) {
return;
}
ton_api::downcast_call(*B.move_as_ok(), [src, Self = this](auto &obj) { Self->process_broadcast(src, obj); });
}
void FullNodePrivateOverlayV2::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno,
td::BufferSlice data) {
if (!inited_) {
return;
}
VLOG(FULL_NODE_DEBUG) << "Sending newShardBlockBroadcast in private overlay: " << block_id.to_str();
auto B = create_serialize_tl_object<ton_api::tonNode_newShardBlockBroadcast>(
create_tl_object<ton_api::tonNode_newShardBlock>(create_tl_block_id(block_id), cc_seqno, std::move(data)));
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_ex, local_id_, overlay_id_,
local_id_.pubkey_hash(), 0, std::move(B));
} else {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), std::move(B));
}
}
void FullNodePrivateOverlayV2::send_broadcast(BlockBroadcast broadcast) {
if (!inited_) {
return;
}
VLOG(FULL_NODE_DEBUG) << "Sending block broadcast in private overlay (with compression): "
<< broadcast.block_id.to_str();
auto B = serialize_block_broadcast(broadcast, true); // compression_enabled = true
if (B.is_error()) {
VLOG(FULL_NODE_WARNING) << "failed to serialize block broadcast: " << B.move_as_error();
return;
}
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
}
void FullNodePrivateOverlayV2::send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno,
td::uint32 validator_set_hash, td::BufferSlice data) {
if (!inited_) {
return;
}
auto B =
serialize_block_candidate_broadcast(block_id, cc_seqno, validator_set_hash, data, true); // compression enabled
if (B.is_error()) {
VLOG(FULL_NODE_WARNING) << "failed to serialize block candidate broadcast: " << B.move_as_error();
return;
}
VLOG(FULL_NODE_DEBUG) << "Sending newBlockCandidate in private overlay (with compression): " << block_id.to_str();
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, local_id_, overlay_id_,
local_id_.pubkey_hash(), overlay::Overlays::BroadcastFlagAnySender(), B.move_as_ok());
}
void FullNodePrivateOverlayV2::start_up() {
std::sort(nodes_.begin(), nodes_.end());
nodes_.erase(std::unique(nodes_.begin(), nodes_.end()), nodes_.end());
std::vector<td::Bits256> nodes, senders;
for (const adnl::AdnlNodeIdShort &id : nodes_) {
nodes.push_back(id.bits256_value());
}
for (const adnl::AdnlNodeIdShort &id : senders_) {
senders.push_back(id.bits256_value());
}
auto X = create_hash_tl_object<ton_api::tonNode_privateBlockOverlayIdV2>(
zero_state_file_hash_, shard_.workchain, shard_.shard, std::move(nodes), std::move(senders));
td::BufferSlice b{32};
b.as_slice().copy_from(as_slice(X));
overlay_id_full_ = overlay::OverlayIdFull{std::move(b)};
overlay_id_ = overlay_id_full_.compute_short_id();
try_init();
}
void FullNodePrivateOverlayV2::try_init() {
// Sometimes adnl id is added to validator engine later (or not at all)
td::actor::send_closure(
adnl_, &adnl::Adnl::check_id_exists, local_id_, [SelfId = actor_id(this)](td::Result<bool> R) {
if (R.is_ok() && R.ok()) {
td::actor::send_closure(SelfId, &FullNodePrivateOverlayV2::init);
} else {
delay_action([SelfId]() { td::actor::send_closure(SelfId, &FullNodePrivateOverlayV2::try_init); },
td::Timestamp::in(30.0));
}
});
}
void FullNodePrivateOverlayV2::init() {
LOG(FULL_NODE_INFO) << "Creating private block overlay for shard " << shard_.to_str() << ", adnl_id=" << local_id_
<< " : " << nodes_.size() << " nodes";
class Callback : public overlay::Overlays::Callback {
public:
void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
}
void receive_query(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
}
void receive_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
td::actor::send_closure(node_, &FullNodePrivateOverlayV2::receive_broadcast, src, std::move(data));
}
void check_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
td::Promise<td::Unit> promise) override {
}
void get_stats_extra(td::Promise<std::string> promise) override {
td::actor::send_closure(node_, &FullNodePrivateOverlayV2::get_stats_extra, std::move(promise));
}
Callback(td::actor::ActorId<FullNodePrivateOverlayV2> node) : node_(node) {
}
private:
td::actor::ActorId<FullNodePrivateOverlayV2> node_;
};
std::map<PublicKeyHash, td::uint32> authorized_keys;
for (const adnl::AdnlNodeIdShort &sender : senders_) {
authorized_keys[sender.pubkey_hash()] = overlay::Overlays::max_fec_broadcast_size();
}
overlay::OverlayPrivacyRules rules{overlay::Overlays::max_fec_broadcast_size(), 0, std::move(authorized_keys)};
std::string scope = PSTRING() << R"({ "type": "private-blocks-v2", "shard_id": )" << shard_.shard
<< ", \"workchain_id\": " << shard_.workchain << " }";
td::actor::send_closure(overlays_, &overlay::Overlays::create_private_overlay, local_id_, overlay_id_full_.clone(),
nodes_, std::make_unique<Callback>(actor_id(this)), rules, std::move(scope));
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, local_id_);
td::actor::send_closure(rldp2_, &rldp2::Rldp::add_id, local_id_);
inited_ = true;
}
void FullNodePrivateOverlayV2::tear_down() {
if (inited_) {
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, local_id_, overlay_id_);
}
}
void FullNodePrivateOverlayV2::get_stats_extra(td::Promise<std::string> promise) {
auto res = create_tl_object<ton_api::engine_validator_privateBlockOverlayV2Stats>();
res->shard_ = shard_.to_str();
for (const auto &x : nodes_) {
res->nodes_.push_back(x.bits256_value());
}
for (const auto &x : senders_) {
res->senders_.push_back(x.bits256_value());
}
res->created_at_ = created_at_;
promise.set_result(td::json_encode<std::string>(td::ToJson(*res), true));
}
td::actor::ActorId<FullNodePrivateOverlayV2> FullNodePrivateBlockOverlaysV2::choose_overlay(ShardIdFull shard) {
for (auto &p : id_to_overlays_) {
auto &overlays = p.second.overlays_;
ShardIdFull cur_shard = shard;
while (true) {
auto it = overlays.find(cur_shard);
if (it != overlays.end() && it->second.is_sender_) {
return it->second.overlay_.get();
}
if (cur_shard.pfx_len() == 0) {
break;
}
cur_shard = shard_parent(cur_shard);
}
}
return {};
}
void FullNodePrivateBlockOverlaysV2::update_overlays(
td::Ref<MasterchainState> state, std::set<adnl::AdnlNodeIdShort> my_adnl_ids, const FileHash &zero_state_file_hash,
const td::actor::ActorId<keyring::Keyring> &keyring, const td::actor::ActorId<adnl::Adnl> &adnl,
const td::actor::ActorId<rldp::Rldp> &rldp, const td::actor::ActorId<rldp2::Rldp> &rldp2,
const td::actor::ActorId<overlay::Overlays> &overlays,
const td::actor::ActorId<ValidatorManagerInterface> &validator_manager,
const td::actor::ActorId<FullNode> &full_node) {
if (my_adnl_ids.empty()) {
id_to_overlays_.clear();
return;
}
auto collators = state->get_collator_config(true);
auto all_validators = state->get_total_validator_set(0);
struct OverlayInfo {
std::vector<adnl::AdnlNodeIdShort> nodes, senders;
};
std::map<ShardIdFull, OverlayInfo> overlay_infos;
// Masterchain overlay: all validators + collators
OverlayInfo &mc_overlay = overlay_infos[ShardIdFull(masterchainId)];
for (const auto &x : all_validators->export_vector()) {
td::Bits256 addr = x.addr.is_zero() ? ValidatorFullId(x.key).compute_short_id().bits256_value() : x.addr;
mc_overlay.nodes.emplace_back(addr);
mc_overlay.senders.emplace_back(addr);
}
for (const auto &x : collators.collator_nodes) {
mc_overlay.nodes.emplace_back(x.adnl_id);
}
// Shard overlays: validators of the shard + collators of the shard
// See ValidatorManagerImpl::update_shards
std::set<ShardIdFull> new_shards;
for (auto &v : state->get_shards()) {
ShardIdFull shard = v->shard();
if (shard.is_masterchain()) {
continue;
}
if (v->before_split()) {
ShardIdFull l_shard{shard.workchain, shard_child(shard.shard, true)};
ShardIdFull r_shard{shard.workchain, shard_child(shard.shard, false)};
new_shards.insert(l_shard);
new_shards.insert(r_shard);
} else if (v->before_merge()) {
ShardIdFull p_shard{shard.workchain, shard_parent(shard.shard)};
new_shards.insert(p_shard);
} else {
new_shards.insert(shard);
}
}
for (ShardIdFull shard : new_shards) {
auto val_set = state->get_validator_set(shard);
td::uint32 min_split = state->monitor_min_split_depth(shard.workchain);
OverlayInfo &overlay =
overlay_infos[shard_prefix_length(shard) <= min_split ? shard : shard_prefix(shard, min_split)];
for (const auto &x : val_set->export_vector()) {
td::Bits256 addr = x.addr.is_zero() ? ValidatorFullId(x.key).compute_short_id().bits256_value() : x.addr;
overlay.nodes.emplace_back(addr);
overlay.senders.emplace_back(addr);
}
}
for (auto &p : overlay_infos) {
ShardIdFull shard = p.first;
OverlayInfo &overlay = p.second;
if (!shard.is_masterchain()) {
for (const auto &collator : collators.collator_nodes) {
if (shard_intersects(collator.shard, shard)) {
overlay.nodes.emplace_back(collator.adnl_id);
}
}
}
std::sort(overlay.nodes.begin(), overlay.nodes.end());
overlay.nodes.erase(std::unique(overlay.nodes.begin(), overlay.nodes.end()), overlay.nodes.end());
std::sort(overlay.senders.begin(), overlay.senders.end());
overlay.senders.erase(std::unique(overlay.senders.begin(), overlay.senders.end()), overlay.senders.end());
}
std::map<adnl::AdnlNodeIdShort, Overlays> old_private_block_overlays = std::move(id_to_overlays_);
id_to_overlays_.clear();
for (const auto &p : overlay_infos) {
ShardIdFull shard = p.first;
const OverlayInfo &new_overlay_info = p.second;
for (adnl::AdnlNodeIdShort local_id : new_overlay_info.nodes) {
if (!my_adnl_ids.count(local_id)) {
continue;
}
Overlays::ShardOverlay &new_overlay = id_to_overlays_[local_id].overlays_[shard];
Overlays::ShardOverlay &old_overlay = old_private_block_overlays[local_id].overlays_[shard];
if (!old_overlay.overlay_.empty() && old_overlay.nodes_ == new_overlay_info.nodes &&
old_overlay.senders_ == new_overlay_info.senders) {
new_overlay = std::move(old_overlay);
old_overlay = {};
} else {
new_overlay.nodes_ = new_overlay_info.nodes;
new_overlay.senders_ = new_overlay_info.senders;
new_overlay.is_sender_ = std::binary_search(new_overlay.senders_.begin(), new_overlay.senders_.end(), local_id);
new_overlay.overlay_ = td::actor::create_actor<FullNodePrivateOverlayV2>(
PSTRING() << "BlocksPrivateOverlay" << shard.to_str(), local_id, shard, new_overlay.nodes_,
new_overlay.senders_, zero_state_file_hash, keyring, adnl, rldp, rldp2, overlays, validator_manager,
full_node);
}
}
}
// Delete old overlays, but not immediately
for (auto &p : old_private_block_overlays) {
for (auto &x : p.second.overlays_) {
if (x.second.overlay_.empty()) {
continue;
}
td::actor::ActorId<FullNodePrivateOverlayV2> id = x.second.overlay_.release();
delay_action([id = std::move(id)]() { td::actor::send_closure(id, &FullNodePrivateOverlayV2::destroy); },
td::Timestamp::in(30.0));
}
}
}
void FullNodePrivateBlockOverlaysV2::destroy_overlays() {
id_to_overlays_.clear();
}
} // namespace ton::validator::fullnode

View file

@ -1419,9 +1419,9 @@ td::actor::ActorOwn<FullNodeShard> FullNodeShard::create(
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node, FullNodeShardMode mode) {
return td::actor::create_actor<FullNodeShardImpl>("tonnode", shard, local_id, adnl_id, zero_state_file_hash, config,
keyring, adnl, rldp, rldp2, overlays, validator_manager, client,
full_node, mode);
return td::actor::create_actor<FullNodeShardImpl>(PSTRING() << "tonnode" << shard.to_str(), shard, local_id, adnl_id,
zero_state_file_hash, config, keyring, adnl, rldp, rldp2, overlays,
validator_manager, client, full_node, mode);
}
} // namespace fullnode

View file

@ -198,8 +198,8 @@ void FullNodeImpl::initial_read_complete(BlockHandle top_handle) {
td::actor::send_closure(it->second.actor, &FullNodeShard::set_handle, top_handle, std::move(P));
}
void FullNodeImpl::update_shard_configuration(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards) {
void FullNodeImpl::on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards) {
CHECK(shards_to_monitor.count(ShardIdFull(masterchainId)));
std::set<ShardIdFull> new_shards;
std::map<ShardIdFull, FullNodeShardMode> new_active;
@ -232,7 +232,7 @@ void FullNodeImpl::update_shard_configuration(td::Ref<MasterchainState> state, s
set_active(cut_shard(shard), FullNodeShardMode::active_temp);
}
auto info_set_mode = [&](ShardIdFull shard, ShardInfo& info, FullNodeShardMode mode) {
auto info_set_mode = [&](ShardIdFull shard, ShardInfo &info, FullNodeShardMode mode) {
if (info.mode == mode) {
return;
}
@ -251,7 +251,7 @@ void FullNodeImpl::update_shard_configuration(td::Ref<MasterchainState> state, s
info.exists = true;
}
for (auto& p : shards_) {
for (auto &p : shards_) {
ShardIdFull shard = p.first;
ShardInfo &info = p.second;
info.exists = new_shards.count(shard);
@ -259,7 +259,7 @@ void FullNodeImpl::update_shard_configuration(td::Ref<MasterchainState> state, s
info_set_mode(shard, info, it == new_active.end() ? FullNodeShardMode::inactive : it->second);
}
for (const auto& s : new_active) {
for (const auto &s : new_active) {
info_set_mode(s.first, shards_[s.first], s.second);
}
@ -276,21 +276,25 @@ void FullNodeImpl::update_shard_configuration(td::Ref<MasterchainState> state, s
}
}
std::set<adnl::AdnlNodeIdShort> my_adnl_ids;
for (const auto &p : local_collator_nodes_) {
my_adnl_ids.insert(p.first);
}
for (auto key : local_keys_) {
auto it = current_validators_.find(key);
if (it != current_validators_.end()) {
my_adnl_ids.insert(it->second);
if (!use_old_private_overlays_) {
std::set<adnl::AdnlNodeIdShort> my_adnl_ids;
my_adnl_ids.insert(adnl_id_);
for (const auto &p : local_collator_nodes_) {
my_adnl_ids.insert(p.first);
}
}
if (use_old_private_overlays_) {
private_block_overlays_v2_.destroy_overlays();
} else {
private_block_overlays_v2_.update_overlays(state, std::move(my_adnl_ids), zero_state_file_hash_, keyring_, adnl_,
rldp_, rldp2_, overlays_, validator_manager_, actor_id(this));
for (auto key : local_keys_) {
auto it = current_validators_.find(key);
if (it != current_validators_.end()) {
my_adnl_ids.insert(it->second);
}
}
std::set<ShardIdFull> monitoring_shards;
for (ShardIdFull shard : shards_to_monitor) {
monitoring_shards.insert(cut_shard(shard));
}
fast_sync_overlays_.update_overlays(state, std::move(my_adnl_ids), std::move(monitoring_shards),
zero_state_file_hash_, keyring_, adnl_, overlays_, validator_manager_,
actor_id(this));
}
}
@ -348,9 +352,9 @@ void FullNodeImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_s
td::actor::send_closure(private_block_overlays_.begin()->second,
&FullNodePrivateBlockOverlay::send_shard_block_info, block_id, cc_seqno, data.clone());
}
auto private_overlay = private_block_overlays_v2_.choose_overlay(ShardIdFull(masterchainId));
auto private_overlay = fast_sync_overlays_.choose_overlay(ShardIdFull(masterchainId));
if (!private_overlay.empty()) {
td::actor::send_closure(private_overlay, &FullNodePrivateOverlayV2::send_shard_block_info, block_id, cc_seqno,
td::actor::send_closure(private_overlay, &FullNodeFastSyncOverlay::send_shard_block_info, block_id, cc_seqno,
data.clone());
}
td::actor::send_closure(shard, &FullNodeShard::send_shard_block_info, block_id, cc_seqno, std::move(data));
@ -368,9 +372,9 @@ void FullNodeImpl::send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_se
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_block_candidate,
block_id, cc_seqno, validator_set_hash, data.clone());
}
auto private_overlay = private_block_overlays_v2_.choose_overlay(block_id.shard_full());
auto private_overlay = fast_sync_overlays_.choose_overlay(block_id.shard_full());
if (!private_overlay.empty()) {
td::actor::send_closure(private_overlay, &FullNodePrivateOverlayV2::send_block_candidate, block_id, cc_seqno,
td::actor::send_closure(private_overlay, &FullNodeFastSyncOverlay::send_block_candidate, block_id, cc_seqno,
validator_set_hash, data.clone());
}
if (broadcast_block_candidates_in_public_overlay_) {
@ -393,9 +397,9 @@ void FullNodeImpl::send_broadcast(BlockBroadcast broadcast, bool custom_overlays
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_broadcast,
broadcast.clone());
}
auto private_overlay = private_block_overlays_v2_.choose_overlay(broadcast.block_id.shard_full());
auto private_overlay = fast_sync_overlays_.choose_overlay(broadcast.block_id.shard_full());
if (!private_overlay.empty()) {
td::actor::send_closure(private_overlay, &FullNodePrivateOverlayV2::send_broadcast, broadcast.clone());
td::actor::send_closure(private_overlay, &FullNodeFastSyncOverlay::send_broadcast, broadcast.clone());
}
td::actor::send_closure(shard, &FullNodeShard::send_broadcast, std::move(broadcast));
}
@ -645,9 +649,9 @@ void FullNodeImpl::start_up() {
void initial_read_complete(BlockHandle handle) override {
td::actor::send_closure(id_, &FullNodeImpl::initial_read_complete, handle);
}
void update_shard_configuration(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards) override {
td::actor::send_closure(id_, &FullNodeImpl::update_shard_configuration, std::move(state),
void on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards) override {
td::actor::send_closure(id_, &FullNodeImpl::on_new_masterchain_block, std::move(state),
std::move(shards_to_monitor), std::move(temporary_shards));
}
void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) override {

View file

@ -92,6 +92,9 @@ class FullNode : public td::actor::Actor {
virtual void process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno,
td::uint32 validator_set_hash, td::BufferSlice data) = 0;
virtual void import_fast_sync_member_certificate(adnl::AdnlNodeIdShort local_id,
overlay::OverlayMemberCertificate cert) = 0;
static constexpr td::uint32 max_block_size() {
return 4 << 20;
}

View file

@ -24,7 +24,7 @@
#include "interfaces/proof.h"
#include "interfaces/shard.h"
#include "full-node-private-overlay.hpp"
#include "full-node-private-overlay-v2.hpp"
#include "full-node-fast-sync-overlays.hpp"
#include <map>
#include <set>
@ -47,9 +47,8 @@ class FullNodeImpl : public FullNode {
void add_collator_adnl_id(adnl::AdnlNodeIdShort id) override;
void del_collator_adnl_id(adnl::AdnlNodeIdShort id) override;
void sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
td::uint32 expiry_at, td::uint32 max_size,
td::Promise<td::BufferSlice> promise) override;
void sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key, td::uint32 expiry_at,
td::uint32 max_size, td::Promise<td::BufferSlice> promise) override;
void import_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
std::shared_ptr<ton::overlay::Certificate> cert,
td::Promise<td::Unit> promise) override;
@ -60,7 +59,7 @@ class FullNodeImpl : public FullNode {
void add_custom_overlay(CustomOverlayParams params, td::Promise<td::Unit> promise) override;
void del_custom_overlay(std::string name, td::Promise<td::Unit> promise) override;
void update_shard_configuration(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor,
void on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards);
void sync_completed();
@ -95,6 +94,11 @@ class FullNodeImpl : public FullNode {
void process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
td::BufferSlice data) override;
void import_fast_sync_member_certificate(adnl::AdnlNodeIdShort local_id,
overlay::OverlayMemberCertificate cert) override {
fast_sync_overlays_.add_member_certificate(local_id, std::move(cert));
}
void start_up() override;
FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
@ -145,12 +149,13 @@ class FullNodeImpl : public FullNode {
FullNodeConfig config_;
// Private overlays:
// Old overlays - one overlay for all validators
// New overlays (v2) - overlay per shard (monitor_min_split depth).
bool use_old_private_overlays_ = false; // TODO: set from config
// Old overlays - one private overlay for all validators
// New overlays (fast sync overlays) - semiprivate overlay per shard (monitor_min_split depth)
// for validators and authorized nodes
bool use_old_private_overlays_ = false; // TODO: set from config or something
std::map<PublicKeyHash, td::actor::ActorOwn<FullNodePrivateBlockOverlay>> private_block_overlays_;
bool broadcast_block_candidates_in_public_overlay_ = false;
FullNodePrivateBlockOverlaysV2 private_block_overlays_v2_;
FullNodeFastSyncOverlays fast_sync_overlays_;
struct CustomOverlayInfo {
CustomOverlayParams params_;

View file

@ -57,6 +57,8 @@ using ValidateCandidateResult = td::Variant<UnixTime, CandidateReject>;
class ValidatorManager : public ValidatorManagerInterface {
public:
virtual void init_last_masterchain_state(td::Ref<MasterchainState> state) {
}
virtual void set_block_state(BlockHandle handle, td::Ref<ShardState> state,
td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void get_cell_db_reader(td::Promise<std::shared_ptr<vm::CellDbReader>> promise) = 0;
@ -140,7 +142,6 @@ class ValidatorManager : public ValidatorManagerInterface {
virtual void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) = 0;
virtual void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) = 0;
virtual void update_shard_configuration(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor) = 0;
virtual void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) = 0;
virtual void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) = 0;

View file

@ -272,8 +272,6 @@ class ValidatorManagerImpl : public ValidatorManager {
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
void update_shard_configuration(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor) override {
}
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override {
UNREACHABLE();

View file

@ -344,9 +344,6 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override {
UNREACHABLE();
}
void update_shard_configuration(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor) override {
UNREACHABLE();
}
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override {
UNREACHABLE();

View file

@ -268,6 +268,7 @@ void ValidatorManagerMasterchainReiniter::downloaded_masterchain_state(td::Ref<S
CHECK(handle_->received_state());
CHECK(handle_->is_applied());
LOG(INFO) << "downloaded masterchain state";
td::actor::send_closure(manager_, &ValidatorManager::init_last_masterchain_state, state_);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::downloaded_all_shards);

View file

@ -1740,6 +1740,7 @@ void ValidatorManagerImpl::send_top_shard_block_description(td::Ref<ShardTopBloc
} else {
out_shard_blocks_[ShardTopBlockDescriptionId{desc->block_id().shard_full(), desc->catchain_seqno()}] = desc;
callback_->send_shard_block_info(desc->block_id(), desc->catchain_seqno(), desc->serialize());
add_shard_block_description(desc);
}
}
@ -1826,6 +1827,14 @@ void ValidatorManagerImpl::start_up() {
alarm_timestamp().relax(check_waiters_at_);
}
void ValidatorManagerImpl::init_last_masterchain_state(td::Ref<MasterchainState> state) {
if (last_masterchain_state_.not_null()) {
return;
}
last_masterchain_state_ = std::move(state);
update_shard_overlays();
}
void ValidatorManagerImpl::started(ValidatorManagerInitResult R) {
CHECK(R.handle);
CHECK(R.state.not_null());
@ -1873,6 +1882,7 @@ void ValidatorManagerImpl::started(ValidatorManagerInitResult R) {
}
});
td::actor::send_closure(db_, &Db::get_persistent_state_descriptions, std::move(Q));
update_shard_overlays();
}
void ValidatorManagerImpl::read_gc_list(std::vector<ValidatorSessionId> list) {
@ -2049,6 +2059,7 @@ void ValidatorManagerImpl::new_masterchain_block() {
}
}
update_shard_overlays();
update_shards();
update_shard_blocks();
@ -2081,6 +2092,26 @@ void ValidatorManagerImpl::new_masterchain_block() {
}
}
void ValidatorManagerImpl::update_shard_overlays() {
CHECK(last_masterchain_state_.not_null());
std::set<ShardIdFull> shards_to_monitor;
shards_to_monitor.insert(ShardIdFull{masterchainId});
std::set<WorkchainId> workchains;
for (const auto& shard : last_masterchain_state_->get_shards()) {
workchains.insert(shard->shard().workchain);
if (opts_->need_monitor(shard->shard(),last_masterchain_state_)) {
shards_to_monitor.insert(shard->shard());
}
}
for (const auto &[wc, desc] : last_masterchain_state_->get_workchain_list()) {
if (!workchains.count(wc) && desc->active &&
opts_->need_monitor(ShardIdFull{wc, shardIdAll}, last_masterchain_state_)) {
shards_to_monitor.insert(ShardIdFull{wc, shardIdAll});
}
}
callback_->on_new_masterchain_block(last_masterchain_state_, std::move(shards_to_monitor), extra_active_shards_);
}
void ValidatorManagerImpl::update_shards() {
if ((last_masterchain_state_->rotated_all_shards() || last_masterchain_seqno_ == 0) &&
opts_->get_last_fork_masterchain_seqno() <= last_masterchain_seqno_) {
@ -2836,11 +2867,6 @@ void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<Bloc
}
}
void ValidatorManagerImpl::update_shard_configuration(td::Ref<MasterchainState> state,
std::set<ShardIdFull> shards_to_monitor) {
callback_->update_shard_configuration(std::move(state), std::move(shards_to_monitor), extra_active_shards_);
}
void ValidatorManagerImpl::update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) {
td::actor::send_closure(db_, &Db::update_async_serializer_state, std::move(state), std::move(promise));
}

View file

@ -319,6 +319,7 @@ class ValidatorManagerImpl : public ValidatorManager {
std::vector<PerfTimerStats> perf_timer_stats;
void new_masterchain_block();
void update_shard_overlays();
void update_shards();
void update_shard_blocks();
void written_destroyed_validator_sessions(std::vector<td::actor::ActorId<ValidatorGroup>> groups);
@ -521,7 +522,6 @@ class ValidatorManagerImpl : public ValidatorManager {
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
void update_shard_configuration(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor) override;
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) override;
@ -557,6 +557,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void finished_wait_data(BlockHandle handle, td::Result<td::Ref<BlockData>> R);
void start_up() override;
void init_last_masterchain_state(td::Ref<MasterchainState> state) override;
void started(ValidatorManagerInitResult result);
void read_gc_list(std::vector<ValidatorSessionId> list);

View file

@ -70,19 +70,13 @@ void ShardClient::got_init_handle_from_db(BlockHandle handle) {
}
void ShardClient::got_init_state_from_db(td::Ref<MasterchainState> state) {
masterchain_state_ = std::move(state);
build_shard_overlays();
masterchain_state_.clear();
saved_to_db();
}
void ShardClient::start_up_init_mode() {
build_shard_overlays();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ShardClient::applied_all_shards);
td::actor::send_closure(SelfId, &ShardClient::apply_all_shards);
});
td::MultiPromise mp;
@ -166,7 +160,6 @@ void ShardClient::download_masterchain_state() {
void ShardClient::got_masterchain_block_state(td::Ref<MasterchainState> state) {
masterchain_state_ = std::move(state);
build_shard_overlays();
if (started_) {
apply_all_shards();
}
@ -189,7 +182,9 @@ void ShardClient::apply_all_shards() {
ig.add_promise(std::move(P));
auto vec = masterchain_state_->get_shards();
std::set<WorkchainId> workchains;
for (auto &shard : vec) {
workchains.insert(shard->shard().workchain);
if (opts_->need_monitor(shard->shard(), masterchain_state_)) {
auto Q = td::PromiseCreator::lambda([SelfId = actor_id(this), promise = ig.get_promise(),
shard = shard->shard()](td::Result<td::Ref<ShardState>> R) mutable {
@ -203,6 +198,21 @@ void ShardClient::apply_all_shards() {
shard_client_priority(), td::Timestamp::in(1500), std::move(Q));
}
}
for (const auto &[wc, desc] : masterchain_state_->get_workchain_list()) {
if (!workchains.count(wc) && desc->active && opts_->need_monitor(ShardIdFull{wc, shardIdAll}, masterchain_state_)) {
auto Q = td::PromiseCreator::lambda(
[SelfId = actor_id(this), promise = ig.get_promise(), wc](td::Result<td::Ref<ShardState>> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix(PSTRING() << "workchain " << wc << ": "));
} else {
td::actor::send_closure(SelfId, &ShardClient::downloaded_shard_state, R.move_as_ok(), std::move(promise));
}
});
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short,
BlockIdExt{wc, shardIdAll, 0, desc->zerostate_root_hash, desc->zerostate_file_hash},
shard_client_priority(), td::Timestamp::in(1500), std::move(Q));
}
}
}
void ShardClient::downloaded_shard_state(td::Ref<ShardState> state, td::Promise<td::Unit> promise) {
@ -223,7 +233,6 @@ void ShardClient::new_masterchain_block_notification(BlockHandle handle, td::Ref
masterchain_block_handle_ = std::move(handle);
masterchain_state_ = std::move(state);
waiting_ = false;
build_shard_overlays();
apply_all_shards();
}
@ -244,42 +253,6 @@ void ShardClient::get_processed_masterchain_block_id(td::Promise<BlockIdExt> pro
}
}
void ShardClient::build_shard_overlays() {
std::set<ShardIdFull> new_shards_to_monitor;
std::set<WorkchainId> workchains;
auto cur_time = masterchain_state_->get_unix_time();
new_shards_to_monitor.insert(ShardIdFull(masterchainId));
for (const auto &info : masterchain_state_->get_shards()) {
auto shard = info->shard();
workchains.insert(shard.workchain);
if (opts_->need_monitor(shard, masterchain_state_)) {
new_shards_to_monitor.insert(shard);
}
}
std::vector<BlockIdExt> new_workchains;
for (const auto &wpair : masterchain_state_->get_workchain_list()) {
ton::WorkchainId wc = wpair.first;
const block::WorkchainInfo *winfo = wpair.second.get();
auto shard = ShardIdFull(wc);
if (workchains.count(wc) == 0 && winfo->active && winfo->enabled_since <= cur_time &&
opts_->need_monitor(shard, masterchain_state_)) {
new_shards_to_monitor.insert(shard);
if (shards_to_monitor_.count(shard) == 0) {
new_workchains.push_back(BlockIdExt(wc, shardIdAll, 0, winfo->zerostate_root_hash, winfo->zerostate_file_hash));
}
}
}
td::actor::send_closure(manager_, &ValidatorManager::update_shard_configuration, masterchain_state_,
new_shards_to_monitor);
shards_to_monitor_ = std::move(new_shards_to_monitor);
for (BlockIdExt block_id : new_workchains) {
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, block_id, shard_client_priority(),
td::Timestamp::in(60.0), [](td::Result<td::Ref<ShardState>>) {});
}
}
void ShardClient::force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise) {
CHECK(!init_mode_);
CHECK(!started_);
@ -310,7 +283,6 @@ void ShardClient::force_update_shard_client_ex(BlockHandle handle, td::Ref<Maste
masterchain_block_handle_ = std::move(handle);
masterchain_state_ = std::move(state);
promise_ = std::move(promise);
build_shard_overlays();
applied_all_shards();
}

View file

@ -42,8 +42,6 @@ class ShardClient : public td::actor::Actor {
td::Promise<td::Unit> promise_;
std::set<ShardIdFull> shards_to_monitor_ = {ShardIdFull(masterchainId)};
public:
ShardClient(td::Ref<ValidatorManagerOptions> opts, BlockHandle masterchain_block_handle,
td::Ref<MasterchainState> masterchain_state, td::actor::ActorId<ValidatorManager> manager,
@ -64,8 +62,6 @@ class ShardClient : public td::actor::Actor {
return 2;
}
void build_shard_overlays();
void start_up() override;
void start_up_init_mode();
void start_up_init_mode_finished();

View file

@ -169,9 +169,9 @@ class ValidatorManagerInterface : public td::actor::Actor {
virtual ~Callback() = default;
virtual void initial_read_complete(BlockHandle top_masterchain_blocks) = 0;
virtual void update_shard_configuration(td::Ref<ton::validator::MasterchainState> state,
std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards) = 0;
virtual void on_new_masterchain_block(td::Ref<ton::validator::MasterchainState> state,
std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards) = 0;
virtual void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) = 0;
virtual void send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data) = 0;