mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
32
overlay/CMakeLists.txt
Normal file
32
overlay/CMakeLists.txt
Normal 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)
|
||||
|
149
overlay/overlay-broadcast.cpp
Normal file
149
overlay/overlay-broadcast.cpp
Normal 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
|
111
overlay/overlay-broadcast.hpp
Normal file
111
overlay/overlay-broadcast.hpp
Normal 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
|
320
overlay/overlay-fec-broadcast.cpp
Normal file
320
overlay/overlay-fec-broadcast.cpp
Normal 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
|
314
overlay/overlay-fec-broadcast.hpp
Normal file
314
overlay/overlay-fec-broadcast.hpp
Normal 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
74
overlay/overlay-fec.cpp
Normal 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
58
overlay/overlay-fec.hpp
Normal 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
119
overlay/overlay-id.hpp
Normal 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
349
overlay/overlay-manager.cpp
Normal 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
147
overlay/overlay-manager.h
Normal 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
300
overlay/overlay-peers.cpp
Normal 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
544
overlay/overlay.cpp
Normal 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
73
overlay/overlay.h
Normal 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
336
overlay/overlay.hpp
Normal 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
214
overlay/overlays.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue