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

initial commit

This commit is contained in:
initial commit 2019-09-07 14:03:22 +04:00 committed by vvaltman
commit c2da007f40
1610 changed files with 398047 additions and 0 deletions

32
overlay/CMakeLists.txt Normal file
View file

@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
if (NOT OPENSSL_FOUND)
find_package(OpenSSL REQUIRED)
endif()
set(OVERLAY_SOURCE
overlay-manager.cpp
overlay.cpp
overlay-fec.cpp
overlay-fec-broadcast.cpp
overlay-broadcast.cpp
overlay-peers.cpp
overlay-fec.hpp
overlay-broadcast.hpp
overlay-fec-broadcast.hpp
overlay-manager.h
overlay.h
overlay.hpp
overlays.h
)
add_library(overlay STATIC ${OVERLAY_SOURCE})
target_include_directories(overlay PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..
${OPENSSL_INCLUDE_DIR}
)
target_link_libraries(overlay PRIVATE tdutils tdactor adnl tl_api dht fec)

View file

@ -0,0 +1,149 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "overlay-broadcast.hpp"
#include "overlay.hpp"
#include "keys/encryptor.h"
namespace ton {
namespace overlay {
td::Status BroadcastSimple::check_time() {
return overlay_->check_date(date_);
}
td::Status BroadcastSimple::check_duplicate() {
return overlay_->check_delivered(broadcast_hash_);
}
td::Status BroadcastSimple::check_source() {
return overlay_->check_source_eligible(source_, cert_.get(), data_size());
}
td::BufferSlice BroadcastSimple::to_sign() {
return create_serialize_tl_object<ton_api::overlay_broadcast_toSign>(broadcast_hash_, date_);
}
td::Status BroadcastSimple::check_signature() {
TRY_RESULT(encryptor, overlay_->get_encryptor(source_));
return encryptor->check_signature(to_sign().as_slice(), signature_.as_slice());
}
td::Status BroadcastSimple::run_checks() {
TRY_STATUS(check_time());
TRY_STATUS(check_duplicate());
TRY_STATUS(check_source());
TRY_STATUS(check_signature());
return td::Status::OK();
}
td::Status BroadcastSimple::distribute() {
auto B = serialize();
auto nodes = overlay_->get_neighbours(3);
auto manager = overlay_->overlay_manager();
for (auto &n : nodes) {
td::actor::send_closure(manager, &OverlayManager::send_message, n, overlay_->local_id(), overlay_->overlay_id(),
B.clone());
}
return td::Status::OK();
}
tl_object_ptr<ton_api::overlay_broadcast> BroadcastSimple::tl() const {
return create_tl_object<ton_api::overlay_broadcast>(source_.tl(), cert_ ? cert_->tl() : Certificate::empty_tl(),
flags_, data_.clone(), date_, signature_.clone());
}
td::BufferSlice BroadcastSimple::serialize() {
return serialize_tl_object(tl(), true);
}
td::Status BroadcastSimple::create(OverlayImpl *overlay, 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_);
TRY_STATUS(overlay->check_date(broadcast->date_));
TRY_STATUS(overlay->check_delivered(broadcast_hash));
TRY_RESULT(cert, Certificate::create(std::move(broadcast->certificate_)));
auto B = std::make_unique<BroadcastSimple>(broadcast_hash, src, std::move(cert), broadcast->flags_,
std::move(broadcast->data_), broadcast->date_,
std::move(broadcast->signature_), overlay);
TRY_STATUS(B->run());
overlay->register_simple_broadcast(std::move(B));
return td::Status::OK();
}
td::Status BroadcastSimple::create_new(td::actor::ActorId<OverlayImpl> overlay,
td::actor::ActorId<keyring::Keyring> keyring, PublicKeyHash local_id,
td::BufferSlice data, td::uint32 flags) {
auto data_hash = sha256_bits256(data.as_slice());
auto broadcast_hash = compute_broadcast_id(local_id, data_hash, flags);
auto date = static_cast<td::uint32>(td::Clocks::system());
auto B = std::make_unique<BroadcastSimple>(broadcast_hash, PublicKey{}, nullptr, flags, std::move(data), date,
td::BufferSlice{}, nullptr);
auto to_sign = B->to_sign();
auto P = td::PromiseCreator::lambda(
[id = overlay, B = std::move(B)](td::Result<std::pair<td::BufferSlice, PublicKey>> R) mutable {
if (R.is_error()) {
td::actor::send_closure(id, &OverlayImpl::failed_to_create_simple_broadcast, R.move_as_error());
return;
}
auto V = R.move_as_ok();
auto pub_id = V.second;
B->update_source(pub_id);
B->update_signature(std::move(V.first));
td::actor::send_closure(id, &OverlayImpl::created_simple_broadcast, std::move(B));
});
td::actor::send_closure(keyring, &keyring::Keyring::sign_add_get_public_key, local_id, std::move(to_sign),
std::move(P));
return td::Status::OK();
}
Overlay::BroadcastHash BroadcastSimple::compute_broadcast_id(PublicKeyHash source, Overlay::BroadcastDataHash data_hash,
td::uint32 flags) {
auto obj = create_tl_object<ton_api::overlay_broadcast_id>(
(flags & Overlays::BroadcastFlagAnySender()) ? PublicKeyHash::zero().tl() : source.tl(), data_hash, flags);
return get_tl_object_sha_bits256(obj);
}
Overlay::BroadcastHash BroadcastSimple::compute_broadcast_id(PublicKey source, Overlay::BroadcastDataHash data_hash,
td::uint32 flags) {
return compute_broadcast_id(source.compute_short_id(), data_hash, flags);
}
void BroadcastSimple::update_overlay(OverlayImpl *overlay) {
if (overlay_) {
return;
}
overlay_ = overlay;
cert_ = overlay->get_certificate(source_.compute_short_id());
}
void BroadcastSimple::deliver() {
overlay_->deliver_broadcast(source_.compute_short_id(), data_.clone());
}
} // namespace overlay
} // namespace ton

View file

@ -0,0 +1,111 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "auto/tl/ton_api.h"
#include "overlay/overlay.h"
#include "td/utils/List.h"
namespace ton {
namespace overlay {
class OverlayImpl;
class BroadcastSimple : public td::ListNode {
private:
Overlay::BroadcastHash broadcast_hash_;
PublicKey source_;
std::shared_ptr<Certificate> cert_;
td::uint32 flags_;
td::BufferSlice data_;
td::uint32 date_;
td::BufferSlice signature_;
OverlayImpl *overlay_;
td::Status check_time();
td::Status check_duplicate();
td::Status check_source();
td::Status check_signature();
td::Status run_checks();
td::Status distribute();
td::BufferSlice to_sign();
public:
BroadcastSimple(Overlay::BroadcastHash broadcast_hash, PublicKey source, std::shared_ptr<Certificate> cert,
td::uint32 flags, td::BufferSlice data, td::uint32 date, td::BufferSlice signature,
OverlayImpl *overlay)
: broadcast_hash_(broadcast_hash)
, source_(std::move(source))
, cert_(std::move(cert))
, flags_(flags)
, data_(std::move(data))
, date_(date)
, signature_(std::move(signature))
, overlay_(overlay) {
}
Overlay::BroadcastHash get_hash() const {
return broadcast_hash_;
}
td::uint32 data_size() const {
return static_cast<td::uint32>(data_.size());
}
void update_source(PublicKey source) {
source_ = source;
}
void update_signature(td::BufferSlice signature) {
signature_ = std::move(signature);
}
void deliver();
td::Status run() {
TRY_STATUS(run_checks());
TRY_STATUS(distribute());
deliver();
return td::Status::OK();
}
tl_object_ptr<ton_api::overlay_broadcast> tl() const;
td::BufferSlice serialize();
void update_overlay(OverlayImpl *overlay);
static td::Status create(OverlayImpl *overlay, tl_object_ptr<ton_api::overlay_broadcast> broadcast);
static td::Status create_new(td::actor::ActorId<OverlayImpl> overlay, td::actor::ActorId<keyring::Keyring> keyring,
PublicKeyHash local_id, td::BufferSlice data, td::uint32 flags);
static Overlay::BroadcastHash compute_broadcast_id(PublicKey source, Overlay::BroadcastDataHash data_hash,
td::uint32 flags);
static Overlay::BroadcastHash compute_broadcast_id(PublicKeyHash source, Overlay::BroadcastDataHash data_hash,
td::uint32 flags);
static BroadcastSimple *from_list_node(ListNode *node) {
return static_cast<BroadcastSimple *>(node);
}
};
} // namespace overlay
} // namespace ton

View file

@ -0,0 +1,320 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "overlay-fec-broadcast.hpp"
#include "overlay.hpp"
#include "keys/encryptor.h"
namespace ton {
namespace overlay {
td::Result<std::unique_ptr<BroadcastFec>> BroadcastFec::create(Overlay::BroadcastHash hash, PublicKey src,
Overlay::BroadcastDataHash data_hash, td::uint32 flags,
td::uint32 date, fec::FecType fec_type) {
auto F = std::make_unique<BroadcastFec>(hash, std::move(src), data_hash, flags, date, std::move(fec_type));
TRY_STATUS(F->init_fec_type());
TRY_STATUS(F->run_checks());
return std::move(F);
}
td::Status BroadcastFec::run_checks() {
if (fec_type_.size() > Overlays::max_fec_broadcast_size()) {
return td::Status::Error(ErrorCode::protoviolation, "too big fec broadcast");
}
return td::Status::OK();
}
td::Status OverlayFecBroadcastPart::check_time() {
return overlay_->check_date(date_);
}
td::Status OverlayFecBroadcastPart::check_duplicate() {
TRY_STATUS(overlay_->check_delivered(broadcast_hash_));
if (bcast_ && bcast_->received_part(seqno_)) {
return td::Status::Error(ErrorCode::notready, "duplicate part");
}
return td::Status::OK();
}
td::Status OverlayFecBroadcastPart::check_source() {
TRY_STATUS(overlay_->check_source_eligible(source_, cert_.get(), broadcast_size_));
if (bcast_) {
TRY_STATUS(bcast_->is_eligible_sender(source_));
}
return td::Status::OK();
}
td::Status OverlayFecBroadcastPart::check_signature() {
TRY_RESULT(encryptor, overlay_->get_encryptor(source_));
return encryptor->check_signature(to_sign().as_slice(), signature_.as_slice());
}
td::Status OverlayFecBroadcastPart::run_checks() {
TRY_STATUS(check_time());
TRY_STATUS(check_duplicate());
TRY_STATUS(check_source());
TRY_STATUS(check_signature());
return td::Status::OK();
}
td::Status OverlayFecBroadcastPart::apply() {
if (!bcast_) {
bcast_ = overlay_->get_fec_broadcast(broadcast_hash_);
}
if (!bcast_) {
if (is_short_) {
return td::Status::Error(ErrorCode::protoviolation, "short broadcast part for incomplete broadcast");
}
TRY_RESULT(B, BroadcastFec::create(broadcast_hash_, source_, broadcast_data_hash_, flags_, date_, fec_type_));
bcast_ = B.get();
overlay_->register_fec_broadcast(std::move(B));
}
if (bcast_->received_part(seqno_)) {
return td::Status::Error(ErrorCode::notready, "duplicate part");
} else {
bcast_->add_received_part(seqno_);
}
if (!bcast_->finalized() && is_short_) {
return td::Status::Error(ErrorCode::protoviolation, "short broadcast part for incomplete broadcast");
}
if (!bcast_->finalized()) {
TRY_STATUS(bcast_->add_part(seqno_, data_.clone()));
auto R = bcast_->finish();
if (R.is_error()) {
auto S = R.move_as_error();
if (S.code() != ErrorCode::notready) {
return S;
}
} else {
overlay_->deliver_broadcast(bcast_->get_source().compute_short_id(), R.move_as_ok());
}
}
return td::Status::OK();
}
td::Status OverlayFecBroadcastPart::distribute() {
auto B = export_serialized();
auto nodes = overlay_->get_neighbours(5);
auto manager = overlay_->overlay_manager();
td::BufferSlice data;
td::BufferSlice data_short;
for (auto &n : nodes) {
if (bcast_->neighbour_completed(n)) {
continue;
}
if (bcast_->neighbour_received(n)) {
if (data_short.size() == 0) {
data_short = export_serialized_short();
}
td::actor::send_closure(manager, &OverlayManager::send_message, n, overlay_->local_id(), overlay_->overlay_id(),
data_short.clone());
} else {
if (data.size() == 0) {
data = export_serialized();
}
if (broadcast_hash_.count_leading_zeroes() >= 12) {
VLOG(OVERLAY_INFO) << "broadcast " << broadcast_hash_ << ": sending part " << part_hash_ << " to " << n;
}
td::actor::send_closure(manager, &OverlayManager::send_message, n, overlay_->local_id(), overlay_->overlay_id(),
data.clone());
}
}
return td::Status::OK();
}
tl_object_ptr<ton_api::overlay_broadcastFec> OverlayFecBroadcastPart::export_tl() {
if (data_.size() == 0) {
data_ = bcast_->get_part(seqno_);
}
return create_tl_object<ton_api::overlay_broadcastFec>(
source_.tl(), cert_ ? cert_->tl() : Certificate::empty_tl(), bcast_->get_data_hash(), bcast_->get_size(),
bcast_->get_flags(), data_.clone(), seqno_, bcast_->get_fec_type().tl(), bcast_->get_date(), signature_.clone());
}
tl_object_ptr<ton_api::overlay_broadcastFecShort> OverlayFecBroadcastPart::export_tl_short() {
return create_tl_object<ton_api::overlay_broadcastFecShort>(
source_.tl(), cert_ ? cert_->tl() : Certificate::empty_tl(), broadcast_hash_, part_data_hash_, seqno_,
signature_.clone());
}
td::BufferSlice OverlayFecBroadcastPart::export_serialized() {
return serialize_tl_object(export_tl(), true);
}
td::BufferSlice OverlayFecBroadcastPart::export_serialized_short() {
return serialize_tl_object(export_tl_short(), true);
}
td::BufferSlice OverlayFecBroadcastPart::to_sign() {
auto obj = create_tl_object<ton_api::overlay_broadcast_toSign>(part_hash_, date_);
return serialize_tl_object(obj, true);
}
td::Status OverlayFecBroadcastPart::create(OverlayImpl *overlay,
tl_object_ptr<ton_api::overlay_broadcastFec> broadcast) {
TRY_STATUS(overlay->check_date(broadcast->date_));
auto source = PublicKey{broadcast->src_};
auto part_data_hash = sha256_bits256(broadcast->data_.as_slice());
TRY_RESULT(fec_type, fec::FecType::create(std::move(broadcast->fec_)));
auto broadcast_hash =
compute_broadcast_id(source, fec_type, broadcast->data_hash_, broadcast->data_size_, broadcast->flags_);
auto part_hash = compute_broadcast_part_id(broadcast_hash, part_data_hash, broadcast->seqno_);
if (broadcast_hash.count_leading_zeroes() >= 12) {
VLOG(OVERLAY_INFO) << "broadcast " << broadcast_hash << ": received part " << part_hash;
}
TRY_STATUS(overlay->check_delivered(broadcast_hash));
TRY_RESULT(cert, Certificate::create(std::move(broadcast->certificate_)));
OverlayFecBroadcastPart B{broadcast_hash,
part_hash,
source,
std::move(cert),
broadcast->data_hash_,
static_cast<td::uint32>(broadcast->data_size_),
static_cast<td::uint32>(broadcast->flags_),
part_data_hash,
std::move(broadcast->data_),
static_cast<td::uint32>(broadcast->seqno_),
std::move(fec_type),
static_cast<td::uint32>(broadcast->date_),
std::move(broadcast->signature_),
false,
overlay->get_fec_broadcast(broadcast_hash),
overlay};
TRY_STATUS(B.run());
return td::Status::OK();
}
td::Status OverlayFecBroadcastPart::create(OverlayImpl *overlay,
tl_object_ptr<ton_api::overlay_broadcastFecShort> broadcast) {
auto bcast = overlay->get_fec_broadcast(broadcast->broadcast_hash_);
if (!bcast) {
return td::Status::Error(ErrorCode::notready, "short part of unknown broadcast");
}
if (!bcast->finalized()) {
return td::Status::Error(ErrorCode::protoviolation, "short part of not finished broadcast");
}
TRY_STATUS(overlay->check_date(bcast->get_date()));
auto source = PublicKey{broadcast->src_};
auto part_data_hash = broadcast->part_data_hash_;
auto broadcast_hash = bcast->get_hash();
auto part_hash = compute_broadcast_part_id(broadcast_hash, part_data_hash, broadcast->seqno_);
TRY_STATUS(overlay->check_delivered(broadcast_hash));
TRY_RESULT(cert, Certificate::create(std::move(broadcast->certificate_)));
OverlayFecBroadcastPart B{broadcast_hash,
part_hash,
source,
std::move(cert),
bcast->get_data_hash(),
bcast->get_size(),
bcast->get_flags(),
part_data_hash,
td::BufferSlice{},
static_cast<td::uint32>(broadcast->seqno_),
bcast->get_fec_type(),
bcast->get_date(),
std::move(broadcast->signature_),
true,
bcast,
overlay};
TRY_STATUS(B.run());
return td::Status::OK();
}
td::Status OverlayFecBroadcastPart::create_new(OverlayImpl *overlay, td::actor::ActorId<OverlayImpl> overlay_actor_id,
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) {
auto broadcast_hash = compute_broadcast_id(local_id, fec_type, data_hash, size, flags);
auto part_data_hash = sha256_bits256(part.as_slice());
auto part_hash = compute_broadcast_part_id(broadcast_hash, part_data_hash, seqno);
auto B = std::make_unique<OverlayFecBroadcastPart>(
broadcast_hash, part_hash, PublicKey{}, overlay->get_certificate(local_id), data_hash, size, flags,
part_data_hash, std::move(part), seqno, std::move(fec_type), date, td::BufferSlice{}, false, nullptr, overlay);
auto to_sign = B->to_sign();
auto P = td::PromiseCreator::lambda(
[id = overlay_actor_id, local_id, B = std::move(B)](td::Result<std::pair<td::BufferSlice, PublicKey>> R) mutable {
if (R.is_error()) {
td::actor::send_closure(id, &OverlayImpl::failed_to_create_fec_broadcast, R.move_as_error());
return;
}
auto V = R.move_as_ok();
auto pub_id = V.second;
B->update_source(pub_id);
B->update_signature(std::move(V.first));
td::actor::send_closure(id, &OverlayImpl::created_fec_broadcast, local_id, std::move(B));
});
td::actor::send_closure(overlay->keyring(), &keyring::Keyring::sign_add_get_public_key, local_id, std::move(to_sign),
std::move(P));
return td::Status::OK();
}
Overlay::BroadcastHash OverlayFecBroadcastPart::compute_broadcast_id(PublicKey source, const fec::FecType &fec_type,
Overlay::BroadcastDataHash data_hash,
td::uint32 size, td::uint32 flags) {
return compute_broadcast_id(source.compute_short_id(), fec_type, data_hash, size, flags);
}
Overlay::BroadcastHash OverlayFecBroadcastPart::compute_broadcast_id(PublicKeyHash source, const fec::FecType &fec_type,
Overlay::BroadcastDataHash data_hash,
td::uint32 size, td::uint32 flags) {
return get_tl_object_sha_bits256(create_tl_object<ton_api::overlay_broadcastFec_id>(
(flags & Overlays::BroadcastFlagAnySender()) ? PublicKeyHash::zero().tl() : source.tl(),
get_tl_object_sha_bits256(fec_type.tl()), data_hash, size, flags));
}
Overlay::BroadcastPartHash OverlayFecBroadcastPart::compute_broadcast_part_id(Overlay::BroadcastHash broadcast_hash,
Overlay::BroadcastDataHash data_hash,
td::uint32 seqno) {
return get_tl_object_sha_bits256(
create_tl_object<ton_api::overlay_broadcastFec_partId>(broadcast_hash, data_hash, seqno));
}
void OverlayFecBroadcastPart::update_overlay(OverlayImpl *overlay) {
if (overlay_) {
return;
}
overlay_ = overlay;
cert_ = overlay_->get_certificate(source_.compute_short_id());
}
} // namespace overlay
} // namespace ton

View file

@ -0,0 +1,314 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "auto/tl/ton_api.h"
#include "overlay/overlay.h"
#include "td/utils/List.h"
#include "fec/fec.h"
#include "common/checksum.h"
#include <set>
namespace ton {
namespace overlay {
class OverlayImpl;
class BroadcastFec : public td::ListNode {
public:
bool finalized() const {
return ready_;
}
bool has_encoder() const {
return encoder_ != nullptr;
}
auto get_hash() const {
return hash_;
}
auto get_data_hash() const {
return data_hash_;
}
td::uint32 get_date() const {
return date_;
}
auto get_flags() const {
return flags_;
}
const auto &get_fec_type() const {
return fec_type_;
}
auto get_source() const {
return src_;
}
auto get_size() const {
return fec_type_.size();
}
td::Status is_eligible_sender(PublicKey src) {
if (flags_ & Overlays::BroadcastFlagAnySender()) {
return td::Status::OK();
} else {
if (src == src_) {
return td::Status::OK();
} else {
return td::Status::Error(ErrorCode::protoviolation, "bad source");
}
}
}
td::Status add_part(td::uint32 seqno, td::BufferSlice data) {
CHECK(decoder_);
td::fec::Symbol s;
s.id = seqno;
s.data = std::move(data);
decoder_->add_symbol(std::move(s));
return td::Status::OK();
}
td::Result<td::BufferSlice> finish() {
CHECK(decoder_);
if (!decoder_->may_try_decode()) {
return td::Status::Error(ErrorCode::notready, "need more parts");
}
TRY_RESULT(D, decoder_->try_decode(true));
if (sha256_bits256(D.data.as_slice()) != data_hash_) {
return td::Status::Error(ErrorCode::protoviolation, "bad hash");
}
encoder_ = std::move(D.encoder);
CHECK(encoder_ != nullptr);
ready_ = true;
decoder_ = nullptr;
return std::move(D.data);
}
td::BufferSlice get_part(td::uint32 seqno) {
CHECK(ready_);
CHECK(encoder_ != nullptr);
auto R = encoder_->gen_symbol(seqno);
CHECK(R.id == seqno);
return std::move(R.data);
}
td::Status init_fec_type() {
TRY_RESULT(D, fec_type_.create_decoder());
decoder_ = std::move(D);
return td::Status::OK();
}
td::Status run_checks();
BroadcastFec(Overlay::BroadcastHash hash, PublicKey src, Overlay::BroadcastDataHash data_hash, td::uint32 flags,
td::uint32 date, fec::FecType fec_type)
: hash_(hash)
, data_hash_(data_hash)
, flags_(flags)
, date_(date)
, src_(std::move(src))
, fec_type_(std::move(fec_type)) {
}
static td::Result<std::unique_ptr<BroadcastFec>> create(Overlay::BroadcastHash hash, PublicKey src,
Overlay::BroadcastDataHash data_hash, td::uint32 flags,
td::uint32 date, fec::FecType fec_type);
bool neighbour_received(adnl::AdnlNodeIdShort id) const {
return received_neighbours_.find(id) != received_neighbours_.end();
}
void add_received(adnl::AdnlNodeIdShort id) {
received_neighbours_.insert(id);
}
bool neighbour_completed(adnl::AdnlNodeIdShort id) const {
return completed_neighbours_.find(id) != completed_neighbours_.end();
}
void add_completed(adnl::AdnlNodeIdShort id) {
completed_neighbours_.insert(id);
}
static BroadcastFec *from_list_node(ListNode *node) {
return static_cast<BroadcastFec *>(node);
}
bool received_part(td::uint32 seqno) const {
if (seqno + 64 < next_seqno_) {
return true;
}
if (seqno >= next_seqno_) {
return false;
}
return received_parts_ & (1ull << (next_seqno_ - seqno - 1));
}
void add_received_part(td::uint32 seqno) {
CHECK(!received_part(seqno));
if (seqno < next_seqno_) {
received_parts_ |= (1ull << (next_seqno_ - seqno - 1));
} else {
auto old = next_seqno_;
next_seqno_ = seqno + 1;
if (next_seqno_ - old >= 64) {
received_parts_ = 1;
} else {
received_parts_ = received_parts_ << (next_seqno_ - old);
received_parts_ |= 1;
}
}
}
private:
bool ready_ = false;
Overlay::BroadcastHash hash_;
Overlay::BroadcastDataHash data_hash_;
td::uint32 flags_;
td::uint32 date_;
PublicKey src_;
fec::FecType fec_type_;
std::unique_ptr<td::fec::Decoder> decoder_;
std::unique_ptr<td::fec::Encoder> encoder_;
std::set<adnl::AdnlNodeIdShort> received_neighbours_;
std::set<adnl::AdnlNodeIdShort> completed_neighbours_;
td::uint32 next_seqno_ = 0;
td::uint64 received_parts_ = 0;
};
class OverlayFecBroadcastPart : public td::ListNode {
private:
Overlay::BroadcastHash broadcast_hash_;
Overlay::BroadcastPartHash part_hash_;
PublicKey source_;
std::shared_ptr<Certificate> cert_;
Overlay::BroadcastDataHash broadcast_data_hash_;
td::uint32 broadcast_size_;
td::uint32 flags_;
Overlay::BroadcastDataHash part_data_hash_;
td::BufferSlice data_;
td::uint32 seqno_;
fec::FecType fec_type_;
td::uint32 date_;
td::BufferSlice signature_;
bool is_short_;
BroadcastFec *bcast_;
OverlayImpl *overlay_;
td::Status check_time();
td::Status check_duplicate();
td::Status check_source();
td::Status check_signature();
td::Status run_checks();
td::Status apply();
td::Status distribute();
public:
OverlayFecBroadcastPart(Overlay::BroadcastHash broadcast_hash, Overlay::BroadcastPartHash part_hash, PublicKey source,
std::shared_ptr<Certificate> cert, Overlay::BroadcastDataHash data_hash, td::uint32 data_size,
td::uint32 flags, Overlay::BroadcastDataHash part_data_hash, td::BufferSlice data,
td::uint32 seqno, fec::FecType fec_type, td::uint32 date, td::BufferSlice signature,
bool is_short, BroadcastFec *bcast, OverlayImpl *overlay)
: broadcast_hash_(broadcast_hash)
, part_hash_(part_hash)
, source_(std::move(source))
, cert_(std::move(cert))
, broadcast_data_hash_(data_hash)
, broadcast_size_(data_size)
, flags_(flags)
, part_data_hash_(part_data_hash)
, data_(std::move(data))
, seqno_(seqno)
, fec_type_(std::move(fec_type))
, date_(date)
, signature_(std::move(signature))
, is_short_(is_short)
, bcast_(bcast)
, overlay_(overlay) {
}
td::uint32 data_size() const {
return static_cast<td::uint32>(data_.size());
}
Overlay::BroadcastPartHash get_hash() const {
return part_hash_;
}
void update_source(PublicKey source) {
source_ = source;
}
void update_signature(td::BufferSlice signature) {
signature_ = std::move(signature);
}
void update_overlay(OverlayImpl *overlay);
tl_object_ptr<ton_api::overlay_broadcastFec> export_tl();
tl_object_ptr<ton_api::overlay_broadcastFecShort> export_tl_short();
td::BufferSlice export_serialized();
td::BufferSlice export_serialized_short();
td::BufferSlice to_sign();
td::Status run() {
TRY_STATUS(run_checks());
TRY_STATUS(apply());
TRY_STATUS(distribute());
return td::Status::OK();
}
static td::Status create(OverlayImpl *overlay, tl_object_ptr<ton_api::overlay_broadcastFec> broadcast);
static td::Status create(OverlayImpl *overlay, tl_object_ptr<ton_api::overlay_broadcastFecShort> broadcast);
static td::Status create_new(OverlayImpl *overlay, td::actor::ActorId<OverlayImpl> overlay_actor_id,
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);
static Overlay::BroadcastHash compute_broadcast_id(PublicKey source, const fec::FecType &fec_type,
Overlay::BroadcastDataHash data_hash, td::uint32 size,
td::uint32 flags);
static Overlay::BroadcastHash compute_broadcast_id(PublicKeyHash source, const fec::FecType &fec_type,
Overlay::BroadcastDataHash data_hash, td::uint32 size,
td::uint32 flags);
static Overlay::BroadcastPartHash compute_broadcast_part_id(Overlay::BroadcastHash broadcast_hash,
Overlay::BroadcastDataHash data_hash, td::uint32 seqno);
};
} // namespace overlay
} // namespace ton

74
overlay/overlay-fec.cpp Normal file
View file

@ -0,0 +1,74 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "overlay-fec.hpp"
#include "overlay.hpp"
#include "adnl/utils.hpp"
namespace ton {
namespace overlay {
void OverlayOutboundFecBroadcast::alarm() {
for (td::uint32 i = 0; i < 4; i++) {
auto X = encoder_->gen_symbol(seqno_++);
CHECK(X.data.size() <= 1000);
td::actor::send_closure(overlay_, &OverlayImpl::send_new_fec_broadcast_part, local_id_, data_hash_,
fec_type_.size(), flags_, std::move(X.data), X.id, fec_type_, date_);
}
alarm_timestamp() = td::Timestamp::in(0.010);
if (seqno_ >= to_send_) {
stop();
}
}
void OverlayOutboundFecBroadcast::start_up() {
encoder_->prepare_more_symbols();
alarm();
}
OverlayOutboundFecBroadcast::OverlayOutboundFecBroadcast(td::BufferSlice data, td::uint32 flags,
td::actor::ActorId<OverlayImpl> overlay,
PublicKeyHash local_id)
: flags_(flags) {
CHECK(data.size() <= (1 << 27));
local_id_ = local_id;
overlay_ = std::move(overlay);
date_ = static_cast<td::int32>(td::Clocks::system());
to_send_ = (static_cast<td::uint32>(data.size()) / symbol_size_ + 1) * 2;
data_hash_ = td::sha256_bits256(data);
fec_type_ = td::fec::RaptorQEncoder::Parameters{data.size(), symbol_size_, 0};
auto E = fec_type_.create_encoder(std::move(data));
E.ensure();
encoder_ = E.move_as_ok();
}
td::actor::ActorId<OverlayOutboundFecBroadcast> OverlayOutboundFecBroadcast::create(
td::BufferSlice data, td::uint32 flags, td::actor::ActorId<OverlayImpl> overlay, PublicKeyHash local_id) {
return td::actor::create_actor<OverlayOutboundFecBroadcast>(td::actor::ActorOptions().with_name("bcast"),
std::move(data), flags, overlay, local_id)
.release();
}
} // namespace overlay
} // namespace ton

58
overlay/overlay-fec.hpp Normal file
View file

@ -0,0 +1,58 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "overlay-manager.h"
#include "fec/fec.h"
#include "overlay.h"
namespace ton {
namespace overlay {
class OverlayImpl;
class OverlayOutboundFecBroadcast : public td::actor::Actor {
private:
const td::uint32 symbol_size_ = 768;
td::uint32 to_send_;
td::uint32 seqno_ = 0;
PublicKeyHash local_id_;
Overlay::BroadcastDataHash data_hash_;
td::uint32 flags_ = 0;
td::int32 date_;
std::unique_ptr<td::fec::Encoder> encoder_;
td::actor::ActorId<OverlayImpl> overlay_;
fec::FecType fec_type_;
public:
static td::actor::ActorId<OverlayOutboundFecBroadcast> create(td::BufferSlice data, td::uint32 flags,
td::actor::ActorId<OverlayImpl> overlay,
PublicKeyHash local_id);
OverlayOutboundFecBroadcast(td::BufferSlice data, td::uint32 flags, td::actor::ActorId<OverlayImpl> overlay,
PublicKeyHash local_id);
void alarm() override;
void start_up() override;
};
} // namespace overlay
} // namespace ton

119
overlay/overlay-id.hpp Normal file
View file

@ -0,0 +1,119 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "auto/tl/ton_api.h"
#include "adnl/adnl-node-id.hpp"
#include "overlay/overlays.h"
#include "td/utils/overloaded.h"
#include "keys/encryptor.h"
namespace ton {
namespace overlay {
class OverlayNode {
public:
explicit OverlayNode(adnl::AdnlNodeIdShort self_id, OverlayIdShort overlay) {
source_ = self_id;
overlay_ = overlay;
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()};
}
OverlayNode(td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source, OverlayIdShort overlay,
td::int32 version, td::Slice signature)
: source_(std::move(source)), overlay_(overlay), version_(version), signature_(td::SharedSlice(signature)) {
}
OverlayNode(td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source, OverlayIdShort overlay,
td::int32 version, td::SharedSlice signature)
: source_(std::move(source)), overlay_(overlay), version_(version), signature_(std::move(signature)) {
}
td::Status check_signature() {
td::Status res;
source_.visit(td::overloaded(
[&](const adnl::AdnlNodeIdShort &id) { res = td::Status::Error(ErrorCode::notready, "fullid not set"); },
[&](const adnl::AdnlNodeIdFull &id) {
auto E = id.pubkey().create_encryptor();
if (E.is_error()) {
res = E.move_as_error();
return;
}
auto enc = E.move_as_ok();
res = enc->check_signature(to_sign().as_slice(), signature_.as_slice());
}));
return res;
}
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);
}
void update_adnl_id(adnl::AdnlNodeIdFull node_id) {
source_ = node_id;
}
void update_signature(td::Slice signature) {
signature_ = td::SharedSlice(signature);
}
OverlayIdShort overlay_id() const {
return overlay_;
}
td::int32 version() const {
return version_;
}
td::BufferSlice signature() const {
return signature_.clone_as_buffer_slice();
}
adnl::AdnlNodeIdShort adnl_id_short() const {
adnl::AdnlNodeIdShort res;
source_.visit(td::overloaded([&](const adnl::AdnlNodeIdShort &id) { res = id; },
[&](const adnl::AdnlNodeIdFull &id) { res = id.compute_short_id(); }));
return res;
};
adnl::AdnlNodeIdFull adnl_id_full() const {
adnl::AdnlNodeIdFull res;
source_.visit(td::overloaded([&](const adnl::AdnlNodeIdShort &id) { UNREACHABLE(); },
[&](const adnl::AdnlNodeIdFull &id) { res = id; }));
return res;
};
tl_object_ptr<ton_api::overlay_node> tl() const {
auto obj =
create_tl_object<ton_api::overlay_node>(nullptr, overlay_.tl(), version_, signature_.clone_as_buffer_slice());
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()};
}
private:
td::Variant<adnl::AdnlNodeIdFull, adnl::AdnlNodeIdShort> source_;
OverlayIdShort overlay_;
td::int32 version_;
td::SharedSlice signature_;
};
} // namespace overlay
} // namespace ton

349
overlay/overlay-manager.cpp Normal file
View file

@ -0,0 +1,349 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "overlay-manager.h"
#include "overlay.h"
#include "adnl/utils.hpp"
#include "td/utils/Random.h"
#include "td/db/RocksDb.h"
#include "td/utils/overloaded.h"
#include "keys/encryptor.h"
namespace ton {
namespace overlay {
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);
}
}
}
void OverlayManager::register_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
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()) {
td::actor::send_closure(adnl_, &adnl::Adnl::subscribe, local_id,
adnl::Adnl::int_to_bytestring(ton_api::overlay_message::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_query::ID),
std::make_unique<AdnlCallback>(actor_id(this)));
}
overlays_[local_id][overlay_id] = std::move(overlay);
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 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));
}
void OverlayManager::delete_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id) {
auto it = overlays_.find(local_id);
if (it != overlays_.end()) {
it->second.erase(overlay_id);
if (it->second.size() == 0) {
td::actor::send_closure(adnl_, &adnl::Adnl::unsubscribe, local_id,
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));
overlays_.erase(it);
}
}
}
void OverlayManager::create_public_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules) {
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)));
}
void OverlayManager::create_private_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules) {
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)));
}
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;
}
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;
return;
}
auto it2 = it->second.find(OverlayIdShort{M->overlay_});
if (it2 == it->second.end()) {
VLOG(OVERLAY_NOTICE) << this << ": message to localid is not in overlay " << M->overlay_ << "@" << dst;
return;
}
td::actor::send_closure(it2->second, &Overlay::receive_message, src, 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;
}
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;
promise.set_error(td::Status::Error(ErrorCode::protoviolation, PSTRING() << "bad local_id " << dst));
return;
}
auto it2 = it->second.find(OverlayIdShort{M->overlay_});
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_));
return;
}
td::actor::send_closure(it2->second, &Overlay::receive_query, src, std::move(data), std::move(promise));
}
void OverlayManager::send_query_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice query, td::uint64 max_answer_size,
td::actor::ActorId<adnl::AdnlSenderInterface> via) {
CHECK(query.size() <= adnl::Adnl::huge_packet_max_size());
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);
}
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());
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()));
}
void OverlayManager::send_broadcast(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, td::BufferSlice object) {
send_broadcast_ex(local_id, overlay_id, local_id.pubkey_hash(), 0, std::move(object));
}
void OverlayManager::send_broadcast_ex(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, PublicKeyHash send_as,
td::uint32 flags, td::BufferSlice object) {
CHECK(object.size() <= Overlays::max_simple_broadcast_size());
auto it = overlays_.find(local_id);
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));
}
}
}
void OverlayManager::send_broadcast_fec(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
td::BufferSlice object) {
send_broadcast_fec_ex(local_id, overlay_id, local_id.pubkey_hash(), 0, std::move(object));
}
void OverlayManager::send_broadcast_fec_ex(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
PublicKeyHash send_as, td::uint32 flags, td::BufferSlice object) {
CHECK(object.size() <= Overlays::max_fec_broadcast_size());
auto it = overlays_.find(local_id);
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));
}
}
}
void OverlayManager::set_privacy_rules(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
OverlayPrivacyRules rules) {
auto it = overlays_.find(local_id);
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));
}
}
}
void OverlayManager::update_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, PublicKeyHash key,
std::shared_ptr<Certificate> cert) {
auto it = overlays_.find(local_id);
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));
}
}
}
void OverlayManager::get_overlay_random_peers(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
td::uint32 max_peers,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) {
auto it = overlays_.find(local_id);
if (it != overlays_.end()) {
auto it2 = it->second.find(overlay_id);
if (it2 != it->second.end()) {
td::actor::send_closure(it2->second, &Overlay::get_overlay_random_peers, max_peers, std::move(promise));
}
}
}
td::actor::ActorOwn<Overlays> Overlays::create(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<dht::Dht> dht) {
return td::actor::create_actor<OverlayManager>("overlaymanager", db_root, keyring, adnl, dht);
}
OverlayManager::OverlayManager(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<dht::Dht> dht)
: db_root_(db_root), keyring_(keyring), adnl_(adnl), dht_node_(dht) {
}
void OverlayManager::start_up() {
std::shared_ptr<td::KeyValue> kv =
std::make_shared<td::RocksDb>(td::RocksDb::open(PSTRING() << db_root_ << "/overlays").move_as_ok());
db_ = DbType{std::move(kv)};
}
void OverlayManager::save_to_db(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
std::vector<OverlayNode> nodes) {
std::vector<tl_object_ptr<ton_api::overlay_node>> nodes_vec;
for (auto &n : nodes) {
nodes_vec.push_back(n.tl());
}
auto obj = create_tl_object<ton_api::overlay_nodes>(std::move(nodes_vec));
auto key = create_hash_tl_object<ton_api::overlay_db_key_nodes>(local_id.bits256_value(), overlay_id.bits256_value());
db_.set(key, create_serialize_tl_object<ton_api::overlay_db_nodes>(std::move(obj)));
}
Certificate::Certificate(PublicKey issued_by, td::int32 expire_at, td::uint32 max_size, td::BufferSlice signature)
: issued_by_(issued_by)
, expire_at_(expire_at)
, max_size_(max_size)
, signature_(td::SharedSlice(signature.as_slice())) {
}
Certificate::Certificate(PublicKeyHash issued_by, td::int32 expire_at, td::uint32 max_size, td::BufferSlice signature)
: issued_by_(issued_by)
, expire_at_(expire_at)
, max_size_(max_size)
, signature_(td::SharedSlice(signature.as_slice())) {
}
void Certificate::set_signature(td::BufferSlice signature) {
signature_ = td::SharedSlice{signature.as_slice()};
}
void Certificate::set_issuer(PublicKey issuer) {
issued_by_ = issuer;
}
td::BufferSlice Certificate::to_sign(OverlayIdShort overlay_id, PublicKeyHash issued_to) const {
return create_serialize_tl_object<ton_api::overlay_certificateId>(overlay_id.tl(), issued_to.tl(), expire_at_,
max_size_);
}
const PublicKeyHash Certificate::issuer_hash() const {
PublicKeyHash r;
issued_by_.visit(
td::overloaded([&](const PublicKeyHash &x) { r = x; }, [&](const PublicKey &x) { r = x.compute_short_id(); }));
return r;
}
const PublicKey &Certificate::issuer() const {
return issued_by_.get<PublicKey>();
}
td::Result<std::shared_ptr<Certificate>> Certificate::create(tl_object_ptr<ton_api::overlay_Certificate> cert) {
std::shared_ptr<Certificate> res;
ton_api::downcast_call(*cert.get(), td::overloaded([&](ton_api::overlay_emptyCertificate &obj) { res = nullptr; },
[&](ton_api::overlay_certificate &obj) {
res = std::make_shared<Certificate>(
PublicKey{obj.issued_by_}, obj.expire_at_,
static_cast<td::uint32>(obj.max_size_),
std::move(obj.signature_));
}));
return std::move(res);
}
td::Status Certificate::check(PublicKeyHash node, OverlayIdShort overlay_id, td::int32 unix_time,
td::uint32 size) const {
if (size > max_size_) {
return td::Status::Error(ErrorCode::protoviolation, "too big broadcast size");
}
if (unix_time > expire_at_) {
return td::Status::Error(ErrorCode::protoviolation, "too old certificate");
}
TRY_RESULT(E, issued_by_.get<PublicKey>().create_encryptor());
auto B = to_sign(overlay_id, node);
TRY_STATUS(E->check_signature(B.as_slice(), signature_.as_slice()));
return td::Status::OK();
}
tl_object_ptr<ton_api::overlay_Certificate> Certificate::tl() const {
return create_tl_object<ton_api::overlay_certificate>(issued_by_.get<PublicKey>().tl(), expire_at_, max_size_,
signature_.clone_as_buffer_slice());
}
tl_object_ptr<ton_api::overlay_Certificate> Certificate::empty_tl() {
return create_tl_object<ton_api::overlay_emptyCertificate>();
}
} // namespace overlay
} // namespace ton

147
overlay/overlay-manager.h Normal file
View file

@ -0,0 +1,147 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include <map>
#include "td/actor/actor.h"
#include "td/db/KeyValueAsync.h"
#include "adnl/adnl.h"
#include "dht/dht.h"
#include "overlays.h"
#include "overlay-id.hpp"
namespace ton {
namespace overlay {
constexpr int VERBOSITY_NAME(OVERLAY_WARNING) = verbosity_WARNING;
constexpr int VERBOSITY_NAME(OVERLAY_NOTICE) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(OVERLAY_INFO) = verbosity_DEBUG;
constexpr int VERBOSITY_NAME(OVERLAY_DEBUG) = verbosity_DEBUG + 1;
constexpr int VERBOSITY_NAME(OVERLAY_EXTRA_DEBUG) = verbosity_DEBUG + 10;
class Overlay;
class OverlayManager : public Overlays {
public:
OverlayManager(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<dht::Dht> dht);
void start_up() override;
void save_to_db(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, std::vector<OverlayNode> nodes);
void update_dht_node(td::actor::ActorId<dht::Dht> dht) override;
void create_public_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules) override;
void create_private_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::vector<adnl::AdnlNodeIdShort> nodes, std::unique_ptr<Callback> callback,
OverlayPrivacyRules rules) 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 {
send_query_via(dst, src, overlay_id, std::move(name), std::move(promise), timeout, std::move(query),
adnl::Adnl::huge_packet_max_size(), adnl_);
}
void send_query_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, std::string name,
td::Promise<td::BufferSlice> promise, td::Timestamp timeout, td::BufferSlice query,
td::uint64 max_answer_size, td::actor::ActorId<adnl::AdnlSenderInterface> via) override;
void send_message(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
td::BufferSlice object) override {
send_message_via(dst, src, overlay_id, std::move(object), adnl_);
}
void send_message_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
td::BufferSlice object, td::actor::ActorId<adnl::AdnlSenderInterface> via) override;
void send_broadcast(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, td::BufferSlice object) override;
void send_broadcast_ex(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, PublicKeyHash send_as, td::uint32 flags,
td::BufferSlice object) override;
void send_broadcast_fec(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, td::BufferSlice object) override;
void send_broadcast_fec_ex(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, PublicKeyHash send_as,
td::uint32 flags, td::BufferSlice object) override;
void set_privacy_rules(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, OverlayPrivacyRules rules) override;
void update_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, PublicKeyHash key,
std::shared_ptr<Certificate> cert) override;
void get_overlay_random_peers(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay, td::uint32 max_peers,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) override;
void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data,
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,
td::actor::ActorOwn<Overlay> overlay);
struct PrintId {};
PrintId print_id() const {
return PrintId{};
}
private:
std::map<adnl::AdnlNodeIdShort, std::map<OverlayIdShort, td::actor::ActorOwn<Overlay>>> overlays_;
std::string db_root_;
td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<adnl::Adnl> adnl_;
td::actor::ActorId<dht::Dht> dht_node_;
using DbType = td::KeyValueAsync<td::Bits256, td::BufferSlice>;
DbType db_;
class AdnlCallback : public adnl::Adnl::Callback {
public:
void receive_message(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data) override {
td::actor::send_closure(id_, &OverlayManager::receive_message, src, dst, std::move(data));
}
void receive_query(adnl::AdnlNodeIdShort src, adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &OverlayManager::receive_query, src, dst, std::move(data), std::move(promise));
}
AdnlCallback(td::actor::ActorId<OverlayManager> id) : id_(id) {
}
private:
td::actor::ActorId<OverlayManager> id_;
};
};
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const OverlayManager::PrintId &id) {
sb << "[overlaymanager]";
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const OverlayManager &manager) {
sb << manager.print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const OverlayManager *manager) {
sb << manager->print_id();
return sb;
}
} // namespace overlay
} // namespace ton

300
overlay/overlay-peers.cpp Normal file
View file

@ -0,0 +1,300 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "overlay.hpp"
namespace ton {
namespace overlay {
void OverlayImpl::del_peer(adnl::AdnlNodeIdShort id) {
auto P = peers_.get(id);
CHECK(P != nullptr);
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);
}
peers_.remove(id);
update_neighbours(0);
}
void OverlayImpl::del_some_peers() {
if (!public_) {
return;
}
while (peers_.size() > max_peers()) {
auto P = get_random_peer();
if (P) {
auto id = P->get_id();
del_peer(id);
}
}
}
void OverlayImpl::do_add_peer(OverlayNode node) {
auto id = node.adnl_id_short();
auto V = peers_.get(id);
if (V) {
VLOG(OVERLAY_DEBUG) << this << ": updating peer " << id << " up to version " << node.version();
V->update(std::move(node));
} else {
VLOG(OVERLAY_DEBUG) << this << ": adding peer " << id << " of version " << node.version();
peers_.insert(id, OverlayPeer(std::move(node)));
del_some_peers();
update_neighbours(0);
}
}
void OverlayImpl::add_peer_in_cont(OverlayNode node) {
CHECK(public_);
do_add_peer(std::move(node));
}
void OverlayImpl::add_peer_in(OverlayNode node) {
CHECK(public_);
if (node.overlay_id() != overlay_id_) {
VLOG(OVERLAY_WARNING) << this << ": received node with bad overlay";
return;
}
auto t = td::Clocks::system();
if (node.version() + 600 < t || node.version() > t + 60) {
VLOG(OVERLAY_INFO) << this << ": ignoring node of too old version " << node.version();
return;
}
auto pub_id = node.adnl_id_full();
if (pub_id.compute_short_id() == local_id_) {
VLOG(OVERLAY_DEBUG) << this << ": ignoring self node";
return;
}
auto S = node.check_signature();
if (S.is_error()) {
VLOG(OVERLAY_WARNING) << this << ": bad signature: " << S;
return;
}
add_peer_in_cont(std::move(node));
}
void OverlayImpl::add_peers(std::vector<OverlayNode> peers) {
for (auto &node : peers) {
add_peer_in(std::move(node));
}
}
void OverlayImpl::add_peer(OverlayNode P) {
add_peer_in(std::move(P));
}
void OverlayImpl::receive_random_peers(adnl::AdnlNodeIdShort src, td::BufferSlice data) {
CHECK(public_);
auto R = fetch_tl_object<ton_api::overlay_nodes>(std::move(data), true);
if (R.is_error()) {
VLOG(OVERLAY_WARNING) << this << ": dropping incorrect answer to overlay.getRandomPeers query from " << src << ": "
<< R.move_as_error();
return;
}
auto res = R.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());
}
}
add_peers(std::move(nodes));
}
void OverlayImpl::send_random_peers_cont(adnl::AdnlNodeIdShort src, OverlayNode node,
td::Promise<td::BufferSlice> promise) {
std::vector<tl_object_ptr<ton_api::overlay_node>> vec;
vec.emplace_back(node.tl());
for (td::uint32 i = 0; i < nodes_to_send(); i++) {
auto P = get_random_peer();
if (P) {
vec.emplace_back(P->get().tl());
} else {
break;
}
}
if (promise) {
auto Q = create_tl_object<ton_api::overlay_nodes>(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) {
if (res.is_error()) {
VLOG(OVERLAY_NOTICE) << oid << ": failed getRandomPeers query: " << res.move_as_error();
return;
}
td::actor::send_closure(SelfId, &OverlayImpl::receive_random_peers, src, res.move_as_ok());
});
auto Q =
create_tl_object<ton_api::overlay_getRandomPeers>(create_tl_object<ton_api::overlay_nodes>(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(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_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) {
return;
}
td::uint32 iter = 0;
while (iter < 10 && (nodes_to_change > 0 || neighbours_.size() < max_neighbours())) {
auto X = peers_.get_random();
if (!X) {
break;
}
if (X->get_id() == local_id_) {
iter++;
continue;
}
if (X->get_version() <= td::Clocks::system() - 600) {
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);
}
peers_.remove(X->get_id());
continue;
}
if (X->is_neighbour()) {
iter++;
continue;
}
if (neighbours_.size() < max_neighbours()) {
VLOG(OVERLAY_INFO) << this << ": adding new neighbour " << X->get_id();
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]);
CHECK(Y != nullptr);
CHECK(Y->is_neighbour());
Y->set_neighbour(false);
neighbours_[i] = X->get_id();
X->set_neighbour(true);
nodes_to_change--;
VLOG(OVERLAY_INFO) << this << ": changing neighbour " << Y->get_id() << " -> " << X->get_id();
}
}
}
OverlayPeer *OverlayImpl::get_random_peer() {
while (peers_.size() > 0) {
auto P = peers_.get_random();
if (public_ && P->get_version() + 3600 < td::Clocks::system()) {
VLOG(OVERLAY_INFO) << this << ": deleting outdated peer " << P->get_id();
del_peer(P->get_id());
} else {
return P;
}
}
return nullptr;
}
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 (peers_.size() > v.size()) {
auto P = peers_.get_random();
if (P->get_version() + 3600 < t) {
VLOG(OVERLAY_INFO) << this << ": deleting outdated peer " << P->get_id();
del_peer(P->get_id());
} else {
bool dup = false;
for (auto &n : v) {
if (n == P->get_id()) {
dup = true;
continue;
}
}
if (!dup) {
v.push_back(P->get_id());
}
}
}
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());
}
}
add_peers(std::move(nodes));
}
}
} // namespace overlay
} // namespace ton

544
overlay/overlay.cpp Normal file
View file

@ -0,0 +1,544 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "td/utils/Random.h"
#include "adnl/utils.hpp"
#include "dht/dht.h"
#include "overlay.hpp"
#include "auto/tl/ton_api.hpp"
#include "keys/encryptor.h"
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) {
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));
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) {
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));
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,
OverlayPrivacyRules rules)
: keyring_(keyring)
, adnl_(adnl)
, manager_(manager)
, dht_node_(dht_node)
, local_id_(local_id)
, id_full_(std::move(overlay_id))
, callback_(std::move(callback))
, public_(pub)
, rules_(std::move(rules)) {
overlay_id_ = id_full_.compute_short_id();
VLOG(OVERLAY_INFO) << this << ": creating " << (public_ ? "public" : "private");
for (auto &node : nodes) {
CHECK(!public_);
auto X = OverlayNode{node, overlay_id_};
do_add_peer(std::move(X));
}
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_) {
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));
send_random_peers(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_);
if (it == broadcasts_.end()) {
VLOG(OVERLAY_NOTICE) << this << ": received getBroadcastQuery(" << query.hash_ << ") from " << src
<< " but broadcast is unknown";
promise.set_value(create_serialize_tl_object<ton_api::overlay_broadcastNotFound>());
return;
}
if (delivered_broadcasts_.find(query.hash_) != delivered_broadcasts_.end()) {
VLOG(OVERLAY_DEBUG) << this << ": received getBroadcastQuery(" << query.hash_ << ") from " << src
<< " but broadcast already deleted";
promise.set_value(create_serialize_tl_object<ton_api::overlay_broadcastNotFound>());
return;
}
VLOG(OVERLAY_DEBUG) << this << ": received getBroadcastQuery(" << query.hash_ << ") from " << src
<< " sending broadcast";
promise.set_value(it->second->serialize());
}
void OverlayImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getBroadcastList &query,
td::Promise<td::BufferSlice> promise) {
VLOG(OVERLAY_WARNING) << this << ": DROPPING getBroadcastList query";
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "dropping get broadcast list query"));
}
/*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, 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;
}
}
auto R = fetch_tl_object<ton_api::Function>(data.clone(), true);
if (R.is_error()) {
// allow custom query to be here
callback_->receive_query(src, overlay_id_, std::move(data), std::move(promise));
return;
}
auto Q = R.move_as_ok();
VLOG(OVERLAY_EXTRA_DEBUG) << this << "query from " << src << ": " << ton_api::to_string(Q);
ton_api::downcast_call(*Q.get(), [&](auto &object) { this->process_query(src, object, std::move(promise)); });
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcast> bcast) {
return BroadcastSimple::create(this, std::move(bcast));
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcastFec> b) {
return OverlayFecBroadcastPart::create(this, std::move(b));
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcastFecShort> b) {
return OverlayFecBroadcastPart::create(this, std::move(b));
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcastNotFound> bcast) {
return td::Status::Error(ErrorCode::protoviolation,
PSTRING() << "received strange message broadcastNotFound from " << message_from);
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_fec_received> msg) {
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 "
<< msg->hash_;
it->second->add_received(message_from);
} else {
VLOG(OVERLAY_DEBUG) << this << ": received fec opt-out message from " << message_from << " for unknown broadcast "
<< msg->hash_;
}
return td::Status::OK();
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_fec_completed> msg) {
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 "
<< msg->hash_;
it->second->add_completed(message_from);
} else {
VLOG(OVERLAY_DEBUG) << this << ": received fec completed message from " << message_from << " for unknown broadcast "
<< msg->hash_;
}
return td::Status::OK();
}
td::Status OverlayImpl::process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_unicast> msg) {
VLOG(OVERLAY_DEBUG) << this << ": received unicast from " << message_from;
callback_->receive_message(message_from, overlay_id_, std::move(msg->data_));
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;
}
}
auto X = fetch_tl_object<ton_api::overlay_Broadcast>(data.clone(), true);
if (X.is_error()) {
VLOG(OVERLAY_DEBUG) << this << ": received custom message";
callback_->receive_message(src, overlay_id_, std::move(data));
return;
}
auto Q = X.move_as_ok();
ton_api::downcast_call(*Q.get(), [Self = this, &Q, &src](auto &object) {
Self->process_broadcast(src, move_tl_object_as<std::remove_reference_t<decltype(object)>>(Q));
});
}
void OverlayImpl::alarm() {
bcast_gc();
if (public_) {
if (peers_.size() > 0) {
auto P = get_random_peer();
if (P) {
send_random_peers(P->get_id(), {});
}
}
if (next_dht_query_.is_in_past()) {
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);
});
td::actor::send_closure(dht_node_, &dht::Dht::get_value, dht::DhtKey{overlay_id_.pubkey_hash(), "nodes", 0},
std::move(P));
next_dht_query_ = td::Timestamp::in(td::Random::fast(60.0, 100.0));
}
if (update_db_at_.is_in_past()) {
if (peers_.size() > 0) {
std::vector<OverlayNode> vec;
for (td::uint32 i = 0; i < 20; i++) {
vec.push_back(get_random_peer()->get());
}
td::actor::send_closure(manager_, &OverlayManager::save_to_db, local_id_, overlay_id_, std::move(vec));
}
update_db_at_ = td::Timestamp::in(60.0);
}
alarm_timestamp() = td::Timestamp::in(1.0);
} else {
update_neighbours(0);
alarm_timestamp() = td::Timestamp::in(60.0 + td::Random::fast(0, 100) * 0.6);
}
}
void OverlayImpl::receive_dht_nodes(td::Result<dht::DhtValue> res, bool dummy) {
CHECK(public_);
if (res.is_ok()) {
auto v = res.move_as_ok();
auto R = fetch_tl_object<ton_api::overlay_nodes>(v.value().clone(), true);
if (R.is_ok()) {
auto r = R.move_as_ok();
VLOG(OVERLAY_INFO) << this << ": received " << r->nodes_.size() << " nodes from overlay";
VLOG(OVERLAY_EXTRA_DEBUG) << this << ": nodes: " << ton_api::to_string(r);
std::vector<OverlayNode> nodes;
for (auto &n : r->nodes_) {
auto N = OverlayNode::create(n);
if (N.is_ok()) {
nodes.emplace_back(N.move_as_ok());
}
}
add_peers(std::move(nodes));
} else {
VLOG(OVERLAY_WARNING) << this << ": incorrect value in DHT for overlay nodes: " << R.move_as_error();
}
} else {
VLOG(OVERLAY_NOTICE) << this << ": can not get value from DHT: " << res.move_as_error();
}
VLOG(OVERLAY_INFO) << this << ": adding self node to DHT overlay's nodes";
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), oid = print_id()](td::Result<OverlayNode> R) {
if (R.is_error()) {
LOG(ERROR) << oid << "cannot get self node";
return;
}
td::actor::send_closure(SelfId, &OverlayImpl::update_dht_nodes, R.move_as_ok());
});
get_self_node(std::move(P));
}
void OverlayImpl::update_dht_nodes(OverlayNode node) {
if (!public_) {
return;
}
auto nodes = create_tl_object<ton_api::overlay_nodes>(std::vector<tl_object_ptr<ton_api::overlay_node>>());
nodes->nodes_.emplace_back(node.tl());
dht::DhtKey dht_key{overlay_id_.pubkey_hash(), "nodes", 0};
auto update_rule = dht::DhtUpdateRuleOverlayNodes::create();
dht::DhtKeyDescription dht_key_descr(std::move(dht_key), id_full_.pubkey(), update_rule.move_as_ok(),
td::BufferSlice());
dht_key_descr.check().ensure();
dht::DhtValue value{std::move(dht_key_descr), serialize_tl_object(nodes, true),
static_cast<td::uint32>(td::Clocks::system() + 3600), td::BufferSlice()};
value.check().ensure();
auto P = td::PromiseCreator::lambda([oid = print_id()](td::Result<td::Unit> res) {
if (res.is_error()) {
VLOG(OVERLAY_NOTICE) << oid << ": error storing to DHT: " << res.move_as_error();
}
});
td::actor::send_closure(dht_node_, &dht::Dht::set_value, std::move(value), std::move(P));
}
void OverlayImpl::bcast_gc() {
while (broadcasts_.size() > max_data_bcasts()) {
auto bcast = BroadcastSimple::from_list_node(bcast_data_lru_.get());
CHECK(bcast);
auto hash = bcast->get_hash();
broadcasts_.erase(hash);
if (delivered_broadcasts_.insert(hash).second) {
bcast_lru_.push(hash);
}
}
while (fec_broadcasts_.size() > 0) {
auto bcast = BroadcastFec::from_list_node(bcast_fec_lru_.prev);
CHECK(bcast);
if (bcast->get_date() > td::Clocks::system() - 60) {
break;
}
auto hash = bcast->get_hash();
CHECK(fec_broadcasts_.count(hash) == 1);
fec_broadcasts_.erase(hash);
if (delivered_broadcasts_.insert(hash).second) {
bcast_lru_.push(hash);
}
}
while (bcast_lru_.size() > max_bcasts()) {
auto Id = bcast_lru_.front();
bcast_lru_.pop();
CHECK(delivered_broadcasts_.erase(Id));
}
CHECK(delivered_broadcasts_.size() == bcast_lru_.size());
}
void OverlayImpl::send_message_to_neighbours(td::BufferSlice data) {
for (auto &n : neighbours_) {
td::actor::send_closure(manager_, &OverlayManager::send_message, n, local_id_, overlay_id_, data.clone());
}
}
void OverlayImpl::send_broadcast(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) {
auto S = BroadcastSimple::create_new(actor_id(this), keyring_, send_as, std::move(data), flags);
if (S.is_error()) {
LOG(WARNING) << "failed to send broadcast: " << S;
}
}
void OverlayImpl::send_broadcast_fec(PublicKeyHash send_as, td::uint32 flags, td::BufferSlice data) {
OverlayOutboundFecBroadcast::create(std::move(data), flags, actor_id(this), send_as);
}
void OverlayImpl::print(td::StringBuilder &sb) {
sb << this;
}
td::Status OverlayImpl::check_date(td::uint32 date) {
auto n = td::Clocks::system();
if (date < n - 20) {
return td::Status::Error(ErrorCode::notready, "too old broadcast");
}
if (date > n + 20) {
return td::Status::Error(ErrorCode::notready, "too new broadcast");
}
return td::Status::OK();
}
td::Status OverlayImpl::check_source_eligible(PublicKey source, const Certificate *cert, td::uint32 size) {
if (size == 0) {
return td::Status::Error(ErrorCode::protoviolation, "empty broadcast");
}
auto short_id = source.compute_short_id();
auto r = rules_.max_size(source.compute_short_id());
if (r >= size) {
return td::Status::OK();
}
if (!cert) {
return td::Status::Error(ErrorCode::protoviolation, "source is not eligible");
}
TRY_STATUS(cert->check(short_id, overlay_id_, static_cast<td::int32>(td::Clocks::system()), size));
auto issuer_short = cert->issuer_hash();
if (rules_.max_size(issuer_short) < size) {
return td::Status::Error(ErrorCode::protoviolation, "bad certificate");
}
return td::Status::OK();
}
td::Status OverlayImpl::check_delivered(BroadcastHash hash) {
if (delivered_broadcasts_.count(hash) == 1 || broadcasts_.count(hash) == 1) {
return td::Status::Error(ErrorCode::notready, "duplicate broadcast");
} else {
return td::Status::OK();
}
}
BroadcastFec *OverlayImpl::get_fec_broadcast(BroadcastHash hash) {
auto it = fec_broadcasts_.find(hash);
if (it == fec_broadcasts_.end()) {
return nullptr;
} else {
return it->second.get();
}
}
void OverlayImpl::register_fec_broadcast(std::unique_ptr<BroadcastFec> bcast) {
auto hash = bcast->get_hash();
bcast_fec_lru_.put(bcast.get());
fec_broadcasts_.emplace(hash, std::move(bcast));
bcast_gc();
}
void OverlayImpl::get_self_node(td::Promise<OverlayNode> promise) {
OverlayNode s{local_id_, overlay_id_};
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));
});
td::actor::send_closure(keyring_, &keyring::Keyring::sign_add_get_public_key, local_id_.pubkey_hash(),
std::move(to_sign), std::move(P));
}
void OverlayImpl::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) {
auto S = OverlayFecBroadcastPart::create_new(this, actor_id(this), local_id, data_hash, size, flags, std::move(part),
seqno, std::move(fec_type), date);
if (S.is_error() && S.code() != ErrorCode::notready) {
LOG(WARNING) << "failed to send broadcast part: " << S;
}
}
void OverlayImpl::deliver_broadcast(PublicKeyHash source, td::BufferSlice data) {
callback_->receive_broadcast(source, overlay_id_, std::move(data));
}
void OverlayImpl::failed_to_create_fec_broadcast(td::Status reason) {
if (reason.code() == ErrorCode::notready) {
LOG(DEBUG) << "failed to receive fec broadcast: " << reason;
} else {
LOG(WARNING) << "failed to receive fec broadcast: " << reason;
}
}
void OverlayImpl::created_fec_broadcast(PublicKeyHash local_id, std::unique_ptr<OverlayFecBroadcastPart> bcast) {
bcast->update_overlay(this);
auto S = bcast->run();
if (S.is_error() && S.code() != ErrorCode::notready) {
LOG(WARNING) << "failed to send fec broadcast: " << S;
}
}
void OverlayImpl::failed_to_create_simple_broadcast(td::Status reason) {
if (reason.code() == ErrorCode::notready) {
LOG(DEBUG) << "failed to send simple broadcast: " << reason;
} else {
LOG(WARNING) << "failed to send simple broadcast: " << reason;
}
}
void OverlayImpl::created_simple_broadcast(std::unique_ptr<BroadcastSimple> bcast) {
bcast->update_overlay(this);
auto S = bcast->run();
register_simple_broadcast(std::move(bcast));
if (S.is_error() && S.code() != ErrorCode::notready) {
LOG(WARNING) << "failed to receive fec broadcast: " << S;
}
}
void OverlayImpl::register_simple_broadcast(std::unique_ptr<BroadcastSimple> bcast) {
auto hash = bcast->get_hash();
bcast_data_lru_.put(bcast.get());
broadcasts_.emplace(hash, std::move(bcast));
bcast_gc();
}
td::Result<Encryptor *> OverlayImpl::get_encryptor(PublicKey source) {
auto short_id = source.compute_short_id();
auto it = encryptor_map_.find(short_id);
if (it != encryptor_map_.end()) {
return it->second->get();
}
TRY_RESULT(e, source.create_encryptor());
auto res = e.get();
auto cache = std::make_unique<CachedEncryptor>(short_id, std::move(e));
encryptor_lru_.put(cache.get());
encryptor_map_.emplace(short_id, std::move(cache));
while (encryptor_map_.size() > max_encryptors()) {
auto x = CachedEncryptor::from_list_node(encryptor_lru_.get());
auto id = x->id();
encryptor_map_.erase(id);
}
return res;
}
std::shared_ptr<Certificate> OverlayImpl::get_certificate(PublicKeyHash source) {
auto it = certs_.find(source);
return (it == certs_.end()) ? nullptr : it->second;
}
void OverlayImpl::set_privacy_rules(OverlayPrivacyRules rules) {
rules_ = std::move(rules);
}
} // namespace overlay
} // namespace ton

73
overlay/overlay.h Normal file
View file

@ -0,0 +1,73 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/buffer.h"
#include "td/utils/int_types.h"
#include "td/actor/actor.h"
#include "adnl/adnl.h"
#include "overlay-manager.h"
namespace ton {
namespace overlay {
class Overlay : public td::actor::Actor {
public:
using BroadcastHash = td::Bits256;
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);
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);
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 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;
virtual void print(td::StringBuilder &sb) = 0;
virtual void get_overlay_random_peers(td::uint32 max_peers,
td::Promise<std::vector<adnl::AdnlNodeIdShort>> promise) = 0;
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_broadcast(td::BufferSlice data) = 0;
//virtual void subscribe(std::unique_ptr<Overlays::Callback> callback) = 0;
};
} // namespace overlay
} // namespace ton

336
overlay/overlay.hpp Normal file
View file

@ -0,0 +1,336 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include <vector>
#include <map>
#include <set>
#include <queue>
#include "overlay.h"
#include "overlay-manager.h"
#include "overlay-fec.hpp"
#include "overlay-broadcast.hpp"
#include "overlay-fec-broadcast.hpp"
#include "overlay-id.hpp"
#include "td/utils/DecTree.h"
#include "td/utils/List.h"
#include "td/utils/overloaded.h"
#include "fec/fec.h"
#include "adnl/utils.hpp"
#include "keys/encryptor.h"
#include "auto/tl/ton_api.h"
#include "auto/tl/ton_api.hpp"
namespace ton {
namespace overlay {
//using OverlayNode = tl_object_ptr<ton_api::overlay_node>;
//using OverlayNodesList = tl_object_ptr<ton_api::overlay_nodes>;
class OverlayImpl;
class OverlayPeer {
public:
adnl::AdnlNodeIdShort get_id() const {
return id_;
}
adnl::AdnlNodeIdFull get_full_id() const {
return node_.adnl_id_full();
}
OverlayNode get() const {
return node_.clone();
}
void update(OverlayNode node) {
CHECK(get_id() == node.adnl_id_short());
if (node.version() > node_.version()) {
node_ = std::move(node);
}
}
OverlayPeer(OverlayNode node) : node_(std::move(node)) {
id_ = node_.adnl_id_short();
}
bool is_neighbour() const {
return is_neighbour_;
}
void set_neighbour(bool value) {
is_neighbour_ = value;
}
td::int32 get_version() const {
return node_.version();
}
private:
OverlayNode node_;
adnl::AdnlNodeIdShort id_;
bool is_neighbour_ = false;
};
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);
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 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 get_self_node(td::Promise<OverlayNode> promise);
void alarm() override;
void start_up() override {
if (public_) {
update_db_at_ = td::Timestamp::in(60.0);
}
alarm_timestamp() = td::Timestamp::in(1);
}
void receive_random_peers(adnl::AdnlNodeIdShort src, td::BufferSlice data);
void send_random_peers(adnl::AdnlNodeIdShort dst, td::Promise<td::BufferSlice> promise);
void send_random_peers_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 receive_dht_nodes(td::Result<dht::DhtValue> res, bool dummy);
void update_dht_nodes(OverlayNode node);
void update_neighbours(td::uint32 nodes_to_change);
void finish_fec_bcast(BroadcastHash id) {
out_fec_bcasts_.erase(id);
}
struct PrintId {
OverlayIdShort overlay_id;
adnl::AdnlNodeIdShort local_id;
};
PrintId print_id() const {
return PrintId{overlay_id_, local_id_};
}
void print(td::StringBuilder &sb) override;
td::Status check_date(td::uint32 date);
td::Status check_source_eligible(PublicKey source, const Certificate *cert, td::uint32 size);
td::Status check_delivered(BroadcastHash hash);
BroadcastFec *get_fec_broadcast(BroadcastHash hash);
void register_fec_broadcast(std::unique_ptr<BroadcastFec> bcast);
void register_simple_broadcast(std::unique_ptr<BroadcastSimple> bcast);
void created_simple_broadcast(std::unique_ptr<BroadcastSimple> bcast);
void failed_to_create_simple_broadcast(td::Status reason);
void created_fec_broadcast(PublicKeyHash local_id, std::unique_ptr<OverlayFecBroadcastPart> bcast);
void failed_to_create_fec_broadcast(td::Status reason);
void deliver_broadcast(PublicKeyHash source, td::BufferSlice data);
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()))]);
}
return vec;
}
}
td::actor::ActorId<OverlayManager> overlay_manager() const {
return manager_;
}
td::actor::ActorId<adnl::Adnl> adnl() const {
return adnl_;
}
td::actor::ActorId<keyring::Keyring> keyring() const {
return keyring_;
}
adnl::AdnlNodeIdShort local_id() const {
return local_id_;
}
OverlayIdShort overlay_id() const {
return overlay_id_;
}
std::shared_ptr<Certificate> get_certificate(PublicKeyHash local_id);
td::Result<Encryptor *> get_encryptor(PublicKey source);
private:
template <class T>
void process_query(adnl::AdnlNodeIdShort src, T &query, td::Promise<td::BufferSlice> promise) {
callback_->receive_query(src, overlay_id_, serialize_tl_object(&query, true), std::move(promise));
}
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_getBroadcast &query,
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::overlay_getBroadcastList &query,
td::Promise<td::BufferSlice> promise);
//void process_query(adnl::AdnlNodeIdShort src, adnl::AdnlQueryId query_id, ton_api::overlay_customQuery &query);
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_broadcast> bcast);
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_broadcastFec> bcast);
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcastFecShort> bcast);
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from,
tl_object_ptr<ton_api::overlay_broadcastNotFound> bcast);
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_fec_received> msg);
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_fec_completed> msg);
td::Status process_broadcast(adnl::AdnlNodeIdShort message_from, tl_object_ptr<ton_api::overlay_unicast> msg);
void do_add_peer(OverlayNode node);
void add_peer_in_cont(OverlayNode node);
void add_peer_in(OverlayNode node);
void add_peer(OverlayNode node);
void add_peers(std::vector<OverlayNode> nodes);
void del_some_peers();
void del_peer(adnl::AdnlNodeIdShort id);
OverlayPeer *get_random_peer();
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 id_full_;
OverlayIdShort overlay_id_;
td::DecTree<adnl::AdnlNodeIdShort, OverlayPeer> peers_;
td::Timestamp next_dht_query_ = td::Timestamp::in(1.0);
td::Timestamp update_db_at_;
std::unique_ptr<Overlays::Callback> callback_;
std::map<BroadcastHash, std::unique_ptr<BroadcastSimple>> broadcasts_;
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_;
std::map<BroadcastHash, td::actor::ActorOwn<OverlayOutboundFecBroadcast>> out_fec_bcasts_;
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};
m.copy_from(src.as_slice());
m.remove_prefix(32);
m.copy_from(data_hash.as_slice());
return td::sha256_bits256(td::Slice(buf, 64));
}
bool public_;
bool semi_public_ = false;
OverlayPrivacyRules rules_;
std::map<PublicKeyHash, std::shared_ptr<Certificate>> certs_;
class CachedEncryptor : public td::ListNode {
public:
Encryptor *get() {
return encryptor_.get();
}
auto id() const {
return id_;
}
CachedEncryptor(PublicKeyHash id, std::unique_ptr<Encryptor> encryptor)
: id_(id), encryptor_(std::move(encryptor)) {
}
static CachedEncryptor *from_list_node(td::ListNode *node) {
return static_cast<CachedEncryptor *>(node);
}
private:
PublicKeyHash id_;
std::unique_ptr<Encryptor> encryptor_;
};
td::ListNode encryptor_lru_;
std::map<PublicKeyHash, std::unique_ptr<CachedEncryptor>> encryptor_map_;
};
} // namespace overlay
} // namespace ton
namespace td {
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::overlay::OverlayImpl::PrintId &id) {
sb << "[overlay " << id.overlay_id << "@" << id.local_id << "]";
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::overlay::OverlayImpl &overlay) {
sb << overlay.print_id();
return sb;
}
inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::overlay::OverlayImpl *overlay) {
sb << overlay->print_id();
return sb;
}
} // namespace td

214
overlay/overlays.h Normal file
View file

@ -0,0 +1,214 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "adnl/adnl.h"
#include "dht/dht.h"
#include "td/actor/actor.h"
#include <map>
namespace ton {
namespace overlay {
class OverlayIdShort {
public:
OverlayIdShort() {
}
explicit OverlayIdShort(td::Bits256 id) : id_(id) {
}
auto bits256_value() const {
return id_;
}
auto pubkey_hash() const {
return PublicKeyHash{id_};
}
auto tl() const {
return id_;
}
bool operator<(const OverlayIdShort &with) const {
return id_ < with.id_;
}
bool operator==(const OverlayIdShort &with) const {
return id_ == with.id_;
}
bool operator!=(const OverlayIdShort &with) const {
return id_ != with.id_;
}
private:
td::Bits256 id_;
};
class OverlayIdFull {
public:
OverlayIdFull() {
}
OverlayIdFull clone() const {
return OverlayIdFull{name_.clone()};
}
explicit OverlayIdFull(td::BufferSlice name) : name_(std::move(name)) {
}
auto pubkey() const {
return PublicKey{pubkeys::Overlay{name_.clone()}};
}
OverlayIdShort compute_short_id() const {
return OverlayIdShort{pubkey().compute_short_id().bits256_value()};
}
private:
td::BufferSlice name_;
};
class OverlayPrivacyRules {
public:
OverlayPrivacyRules() {
}
OverlayPrivacyRules(td::uint32 size) : max_unath_size_(size) {
}
OverlayPrivacyRules(td::uint32 max_size, std::map<PublicKeyHash, td::uint32> authorized_keys)
: max_unath_size_(max_size), authorized_keys_(std::move(authorized_keys)) {
}
td::uint32 max_size(PublicKeyHash hash) {
auto it = authorized_keys_.find(hash);
if (it == authorized_keys_.end()) {
return max_unath_size_;
} else {
return it->second;
}
}
private:
td::uint32 max_unath_size_{0};
std::map<PublicKeyHash, td::uint32> authorized_keys_;
};
class Certificate {
public:
Certificate(PublicKeyHash issued_by, td::int32 expire_at, td::uint32 max_size, td::BufferSlice signature);
Certificate(PublicKey issued_by, td::int32 expire_at, td::uint32 max_size, td::BufferSlice signature);
Certificate() {
}
void set_signature(td::BufferSlice signature);
void set_issuer(PublicKey issuer);
td::BufferSlice to_sign(OverlayIdShort overlay_id, PublicKeyHash issued_to) const;
td::Status check(PublicKeyHash node, OverlayIdShort overlay_id, td::int32 unix_time, td::uint32 size) const;
tl_object_ptr<ton_api::overlay_Certificate> tl() const;
const PublicKey &issuer() const;
const PublicKeyHash issuer_hash() const;
static td::Result<std::shared_ptr<Certificate>> create(tl_object_ptr<ton_api::overlay_Certificate> cert);
static tl_object_ptr<ton_api::overlay_Certificate> empty_tl();
private:
td::Variant<PublicKey, PublicKeyHash> issued_by_;
td::int32 expire_at_;
td::uint32 max_size_;
td::SharedSlice signature_;
};
class Overlays : public td::actor::Actor {
public:
class Callback {
public:
virtual void receive_message(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, td::BufferSlice data) = 0;
virtual void receive_query(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) = 0;
virtual void receive_broadcast(PublicKeyHash src, OverlayIdShort overlay_id, td::BufferSlice data) = 0;
virtual ~Callback() = default;
};
static constexpr td::uint32 max_simple_broadcast_size() {
return 768;
}
static constexpr td::uint32 max_message_size() {
return adnl::Adnl::get_mtu() - 36;
}
static constexpr td::uint32 max_fec_broadcast_size() {
return 16 << 20;
}
static constexpr td::uint32 BroadcastFlagAnySender() {
return 1;
}
static td::actor::ActorOwn<Overlays> create(std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<dht::Dht> dht);
virtual void update_dht_node(td::actor::ActorId<dht::Dht> dht) = 0;
virtual void create_public_overlay(adnl::AdnlNodeIdShort local_id, OverlayIdFull overlay_id,
std::unique_ptr<Callback> callback, OverlayPrivacyRules rules) = 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) = 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,
std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice query) = 0;
virtual void send_query_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
std::string name, td::Promise<td::BufferSlice> promise, td::Timestamp timeout,
td::BufferSlice query, td::uint64 max_answer_size,
td::actor::ActorId<adnl::AdnlSenderInterface> via) = 0;
void send_multiple_messages(std::vector<adnl::AdnlNodeIdShort> dst, adnl::AdnlNodeIdShort src,
OverlayIdShort overlay_id, td::BufferSlice object) {
for (auto &n : dst) {
send_message(n, src, overlay_id, object.clone());
}
}
virtual void send_message(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
td::BufferSlice object) = 0;
virtual void send_message_via(adnl::AdnlNodeIdShort dst, adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id,
td::BufferSlice object, td::actor::ActorId<adnl::AdnlSenderInterface> via) = 0;
virtual void send_broadcast(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, td::BufferSlice object) = 0;
virtual void send_broadcast_ex(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, PublicKeyHash send_as,
td::uint32 flags, td::BufferSlice object) = 0;
virtual void send_broadcast_fec(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, td::BufferSlice object) = 0;
virtual void send_broadcast_fec_ex(adnl::AdnlNodeIdShort src, OverlayIdShort overlay_id, PublicKeyHash send_as,
td::uint32 flags, td::BufferSlice object) = 0;
virtual void set_privacy_rules(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id,
OverlayPrivacyRules rules) = 0;
virtual void update_certificate(adnl::AdnlNodeIdShort local_id, OverlayIdShort overlay_id, PublicKeyHash key,
std::shared_ptr<Certificate> cert) = 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;
};
} // namespace overlay
} // namespace ton
namespace td {
inline StringBuilder &operator<<(StringBuilder &stream, const ton::overlay::OverlayIdShort &value) {
return stream << value.bits256_value();
}
} // namespace td