1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-13 03:32:22 +00:00
ton/validator/full-node-shard.cpp
ton 13140ddf29 updated block header
1. Updated block header, proofs now contain more data
   Notice, that old proofs may become invalid in the future
2. Fixed message routing
3. Fixed block creator id in block header
4. Support for full proofs in tonlib
5. Support for partial state download
6. Some other bugfixes
2019-09-18 21:46:32 +04:00

666 lines
30 KiB
C++

/*
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/SharedSlice.h"
#include "full-node-shard.hpp"
#include "ton/ton-shard.h"
#include "ton/ton-tl.hpp"
#include "adnl/utils.hpp"
#include "net/download-next-block.hpp"
#include "net/download-block.hpp"
#include "net/download-state.hpp"
#include "net/download-proof.hpp"
#include "net/get-next-key-blocks.hpp"
#include "common/delay.h"
namespace ton {
namespace validator {
namespace fullnode {
void FullNodeShardImpl::create_overlay() {
class Callback : public overlay::Overlays::Callback {
public:
void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
// just ignore
}
void receive_query(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(node_, &FullNodeShardImpl::receive_query, src, std::move(data), std::move(promise));
}
void receive_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override {
td::actor::send_closure(node_, &FullNodeShardImpl::receive_broadcast, src, std::move(data));
}
Callback(td::actor::ActorId<FullNodeShardImpl> node) : node_(node) {
}
private:
td::actor::ActorId<FullNodeShardImpl> node_;
};
td::actor::send_closure(overlays_, &overlay::Overlays::create_public_overlay, adnl_id_, overlay_id_full_.clone(),
std::make_unique<Callback>(actor_id(this)), rules_);
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl_id_);
if (cert_) {
td::actor::send_closure(overlays_, &overlay::Overlays::update_certificate, adnl_id_, overlay_id_, local_id_, cert_);
}
}
void FullNodeShardImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) {
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, adnl_id_, overlay_id_);
adnl_id_ = adnl_id;
create_overlay();
}
void FullNodeShardImpl::try_get_next_block(td::Timestamp timeout, td::Promise<ReceivedBlock> promise) {
if (timeout.is_in_past()) {
promise.set_error(td::Status::Error(ErrorCode::timeout, "timeout"));
return;
}
td::actor::create_actor<DownloadNextBlock>("downloadnext", adnl_id_, overlay_id_, handle_, download_next_priority(),
timeout, validator_manager_, rldp_, overlays_, adnl_, std::move(promise))
.release();
}
void FullNodeShardImpl::got_next_block(td::Result<BlockHandle> R) {
if (R.is_error()) {
if (R.error().code() == ErrorCode::timeout) {
get_next_block();
return;
}
}
attempt_ = 0;
R.ensure();
auto old_seqno = handle_->id().id.seqno;
handle_ = R.move_as_ok();
CHECK(handle_->id().id.seqno == old_seqno + 1);
if (promise_) {
if (handle_->unix_time() > td::Clocks::system() - 300) {
promise_.set_value(td::Unit());
} else {
sync_completed_at_ = td::Timestamp::in(60.0);
}
}
get_next_block();
}
void FullNodeShardImpl::get_next_block() {
attempt_++;
auto P = td::PromiseCreator::lambda([validator_manager = validator_manager_, attempt = attempt_,
block_id = handle_->id(), SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
if (R.is_ok()) {
auto P = td::PromiseCreator::lambda([SelfId](td::Result<BlockHandle> R) {
td::actor::send_closure(SelfId, &FullNodeShardImpl::got_next_block, std::move(R));
});
td::actor::send_closure(validator_manager, &ValidatorManagerInterface::validate_block, R.move_as_ok(),
std::move(P));
} else {
auto S = R.move_as_error();
if (S.code() != ErrorCode::notready && S.code() != ErrorCode::timeout) {
VLOG(FULL_NODE_WARNING) << "failed to download next block after " << block_id << ": " << S;
} else {
if ((attempt % 128) == 0) {
VLOG(FULL_NODE_INFO) << "failed to download next block after " << block_id << ": " << S;
} else {
VLOG(FULL_NODE_DEBUG) << "failed to download next block after " << block_id << ": " << S;
}
}
delay_action([SelfId]() mutable { td::actor::send_closure(SelfId, &FullNodeShardImpl::get_next_block); },
td::Timestamp::in(0.1));
}
});
try_get_next_block(td::Timestamp::in(2.0), std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextBlockDescription &query,
td::Promise<td::BufferSlice> promise) {
if (query.prev_block_->workchain_ != masterchainId || static_cast<ShardId>(query.prev_block_->shard_) != shardIdAll) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "next block allowed only for masterchain"));
return;
}
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
auto x = create_serialize_tl_object<ton_api::tonNode_blockDescriptionEmpty>();
promise.set_value(std::move(x));
} else {
auto B = R.move_as_ok();
if (!B->received() || !B->inited_proof()) {
auto x = create_serialize_tl_object<ton_api::tonNode_blockDescriptionEmpty>();
promise.set_value(std::move(x));
} else {
auto x = create_serialize_tl_object<ton_api::tonNode_blockDescription>(create_tl_block_id(B->id()));
promise.set_value(std::move(x));
}
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_next_block,
create_block_id(query.prev_block_), std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlock &query,
td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda([promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
auto x = create_serialize_tl_object<ton_api::tonNode_notFound>();
promise.set_value(std::move(x));
} else {
auto B = R.move_as_ok();
if (!B->received()) {
auto x = create_serialize_tl_object<ton_api::tonNode_notFound>();
promise.set_value(std::move(x));
} else {
auto x = create_serialize_tl_object<ton_api::tonNode_prepared>();
promise.set_value(std::move(x));
}
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
create_block_id(query.block_), false, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlock &query,
td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda([validator_manager = validator_manager_,
promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block"));
} else {
auto B = R.move_as_ok();
if (!B->received()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block"));
} else {
td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_data, B, std::move(promise));
}
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
create_block_id(query.block_), false, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareBlockProof &query,
td::Promise<td::BufferSlice> promise) {
if (query.block_->seqno_ == 0) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "cannot download proof for zero state"));
return;
}
auto P = td::PromiseCreator::lambda([allow_partial = query.allow_partial_, promise = std::move(promise),
validator_manager = validator_manager_](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
auto x = create_serialize_tl_object<ton_api::tonNode_preparedProofEmpty>();
promise.set_value(std::move(x));
return;
} else {
auto handle = R.move_as_ok();
if (!handle || (!handle->inited_proof() && (!allow_partial || !handle->inited_proof_link()))) {
auto x = create_serialize_tl_object<ton_api::tonNode_preparedProofEmpty>();
promise.set_value(std::move(x));
return;
}
if (handle->inited_proof() && handle->id().is_masterchain()) {
auto x = create_serialize_tl_object<ton_api::tonNode_preparedProof>();
promise.set_value(std::move(x));
} else {
auto x = create_serialize_tl_object<ton_api::tonNode_preparedProofLink>();
promise.set_value(std::move(x));
}
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
create_block_id(query.block_), false, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProof &query,
td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise), validator_manager = validator_manager_](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof"));
return;
} else {
auto handle = R.move_as_ok();
if (!handle || !handle->inited_proof()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof"));
return;
}
td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_proof, handle,
std::move(promise));
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
create_block_id(query.block_), false, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadBlockProofLink &query,
td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise), validator_manager = validator_manager_](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof"));
return;
} else {
auto handle = R.move_as_ok();
if (!handle || !handle->inited_proof_link()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "unknown block proof"));
return;
}
td::actor::send_closure(validator_manager, &ValidatorManagerInterface::get_block_proof_link, handle,
std::move(promise));
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_handle,
create_block_id(query.block_), false, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareZeroState &query,
td::Promise<td::BufferSlice> promise) {
auto P =
td::PromiseCreator::lambda([SelfId = actor_id(this), promise = std::move(promise)](td::Result<bool> R) mutable {
if (R.is_error() || !R.move_as_ok()) {
auto x = create_serialize_tl_object<ton_api::tonNode_notFoundState>();
promise.set_value(std::move(x));
return;
}
auto x = create_serialize_tl_object<ton_api::tonNode_preparedState>();
promise.set_value(std::move(x));
});
auto block_id = create_block_id(query.block_);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::check_zero_state_exists, block_id,
std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_preparePersistentState &query,
td::Promise<td::BufferSlice> promise) {
auto P =
td::PromiseCreator::lambda([SelfId = actor_id(this), promise = std::move(promise)](td::Result<bool> R) mutable {
if (R.is_error() || !R.move_as_ok()) {
auto x = create_serialize_tl_object<ton_api::tonNode_notFoundState>();
promise.set_value(std::move(x));
return;
}
auto x = create_serialize_tl_object<ton_api::tonNode_preparedState>();
promise.set_value(std::move(x));
});
auto block_id = create_block_id(query.block_);
auto masterchain_block_id = create_block_id(query.masterchain_block_);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::check_persistent_state_exists, block_id,
masterchain_block_id, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getNextKeyBlockIds &query,
td::Promise<td::BufferSlice> promise) {
auto cnt = static_cast<td::uint32>(query.max_size_);
if (cnt > 8) {
cnt = 8;
}
auto P =
td::PromiseCreator::lambda([promise = std::move(promise), cnt](td::Result<std::vector<BlockIdExt>> R) mutable {
if (R.is_error()) {
LOG(WARNING) << "getnextkey: " << R.move_as_error();
auto x = create_serialize_tl_object<ton_api::tonNode_keyBlocks>(
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>>{}, false, true);
promise.set_value(std::move(x));
return;
}
auto res = R.move_as_ok();
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> v;
for (auto &b : res) {
v.emplace_back(create_tl_block_id(b));
}
auto x = create_serialize_tl_object<ton_api::tonNode_keyBlocks>(std::move(v), res.size() < cnt, false);
promise.set_value(std::move(x));
});
auto block_id = create_block_id(query.block_);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_next_key_blocks, block_id, cnt,
std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadZeroState &query,
td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix("failed to get state from db: "));
return;
}
promise.set_value(R.move_as_ok());
});
auto block_id = create_block_id(query.block_);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_zero_state, block_id, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentState &query,
td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix("failed to get state from db: "));
return;
}
promise.set_value(R.move_as_ok());
});
auto block_id = create_block_id(query.block_);
auto masterchain_block_id = create_block_id(query.masterchain_block_);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state, block_id,
masterchain_block_id, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_downloadPersistentStateSlice &query,
td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::BufferSlice> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix("failed to get state from db: "));
return;
}
promise.set_value(R.move_as_ok());
});
auto block_id = create_block_id(query.block_);
auto masterchain_block_id = create_block_id(query.masterchain_block_);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_persistent_state_slice, block_id,
masterchain_block_id, query.offset_, query.max_size_, std::move(P));
}
void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,
td::Promise<td::BufferSlice> promise) {
auto B = fetch_tl_object<ton_api::Function>(std::move(query), true);
if (B.is_error()) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "cannot parse tonnode query"));
return;
}
ton_api::downcast_call(*B.move_as_ok().get(), [&](auto &obj) { this->process_query(src, obj, std::move(promise)); });
}
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_ihrMessageBroadcast &query) {
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_ihr_message,
std::move(query.message_->data_));
}
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_externalMessageBroadcast &query) {
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_external_message,
std::move(query.message_->data_));
}
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_newShardBlockBroadcast &query) {
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_shard_block,
create_block_id(query.block_->block_), query.block_->cc_seqno_,
std::move(query.block_->data_));
}
void FullNodeShardImpl::process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query) {
std::vector<BlockSignature> signatures;
for (auto &sig : query.signatures_) {
signatures.emplace_back(BlockSignature{sig->who_, std::move(sig->signature_)});
}
BlockIdExt block_id = create_block_id(query.id_);
BlockBroadcast B{block_id,
std::move(signatures),
static_cast<UnixTime>(query.catchain_seqno_),
static_cast<td::uint32>(query.validator_set_hash_),
std::move(query.data_),
std::move(query.proof_)};
auto P = td::PromiseCreator::lambda([](td::Result<td::Unit> R) {});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, std::move(B),
std::move(P));
}
void FullNodeShardImpl::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
auto B = fetch_tl_object<ton_api::tonNode_Broadcast>(std::move(broadcast), true);
if (B.is_error()) {
return;
}
ton_api::downcast_call(*B.move_as_ok().get(), [src, Self = this](auto &obj) { Self->process_broadcast(src, obj); });
}
void FullNodeShardImpl::send_ihr_message(td::BufferSlice data) {
auto B = create_serialize_tl_object<ton_api::tonNode_ihrMessageBroadcast>(
create_tl_object<ton_api::tonNode_ihrMessage>(std::move(data)));
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_ex, adnl_id_, overlay_id_, local_id_, 0,
std::move(B));
} else {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_, 0,
std::move(B));
}
}
void FullNodeShardImpl::send_external_message(td::BufferSlice data) {
auto B = create_serialize_tl_object<ton_api::tonNode_externalMessageBroadcast>(
create_tl_object<ton_api::tonNode_externalMessage>(std::move(data)));
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_ex, adnl_id_, overlay_id_, local_id_, 0,
std::move(B));
} else {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_, 0,
std::move(B));
}
}
void FullNodeShardImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
auto B = create_serialize_tl_object<ton_api::tonNode_newShardBlockBroadcast>(
create_tl_object<ton_api::tonNode_newShardBlock>(create_tl_block_id(block_id), cc_seqno, std::move(data)));
if (B.size() <= overlay::Overlays::max_simple_broadcast_size()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_ex, adnl_id_, overlay_id_, local_id_, 0,
std::move(B));
} else {
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_,
overlay::Overlays::BroadcastFlagAnySender(), std::move(B));
}
}
void FullNodeShardImpl::send_broadcast(BlockBroadcast broadcast) {
std::vector<tl_object_ptr<ton_api::tonNode_blockSignature>> sigs;
for (auto &sig : broadcast.signatures) {
sigs.emplace_back(create_tl_object<ton_api::tonNode_blockSignature>(sig.node, sig.signature.clone()));
}
auto B = create_serialize_tl_object<ton_api::tonNode_blockBroadcast>(
create_tl_block_id(broadcast.block_id), broadcast.catchain_seqno, broadcast.validator_set_hash, std::move(sigs),
broadcast.proof.clone(), broadcast.data.clone());
td::actor::send_closure(overlays_, &overlay::Overlays::send_broadcast_fec_ex, adnl_id_, overlay_id_, local_id_,
overlay::Overlays::BroadcastFlagAnySender(), std::move(B));
}
void FullNodeShardImpl::download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<ReceivedBlock> promise) {
td::actor::create_actor<DownloadBlock>("downloadreq", id, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(),
priority, timeout, validator_manager_, rldp_, overlays_, adnl_,
std::move(promise))
.release();
}
void FullNodeShardImpl::download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
td::actor::create_actor<DownloadState>("downloadstatereq", id, BlockIdExt{}, adnl_id_, overlay_id_,
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
overlays_, adnl_, std::move(promise))
.release();
}
void FullNodeShardImpl::download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) {
td::actor::create_actor<DownloadState>("downloadstatereq", id, masterchain_block_id, adnl_id_, overlay_id_,
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
overlays_, adnl_, std::move(promise))
.release();
}
void FullNodeShardImpl::download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
td::actor::create_actor<DownloadProof>("downloadproofreq", block_id, false, adnl_id_, overlay_id_,
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
overlays_, adnl_, std::move(promise))
.release();
}
void FullNodeShardImpl::download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
td::actor::create_actor<DownloadProof>("downloadproofreq", block_id, true, adnl_id_, overlay_id_,
adnl::AdnlNodeIdShort::zero(), priority, timeout, validator_manager_, rldp_,
overlays_, adnl_, std::move(promise))
.release();
}
void FullNodeShardImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
td::Promise<std::vector<BlockIdExt>> promise) {
td::actor::create_actor<GetNextKeyBlocks>("next", block_id, 16, adnl_id_, overlay_id_, adnl::AdnlNodeIdShort::zero(),
1, timeout, validator_manager_, rldp_, overlays_, adnl_, std::move(promise))
.release();
}
void FullNodeShardImpl::set_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
CHECK(!handle_);
handle_ = std::move(handle);
promise_ = std::move(promise);
get_next_block();
sync_completed_at_ = td::Timestamp::in(60.0);
alarm_timestamp().relax(sync_completed_at_);
}
void FullNodeShardImpl::alarm() {
if (sync_completed_at_ && sync_completed_at_.is_in_past()) {
if (promise_) {
promise_.set_value(td::Unit());
}
sync_completed_at_ = td::Timestamp::never();
}
if (update_certificate_at_ && update_certificate_at_.is_in_past()) {
if (!sign_cert_by_.is_zero()) {
sign_new_certificate(sign_cert_by_);
update_certificate_at_ = td::Timestamp::in(30.0);
} else {
update_certificate_at_ = td::Timestamp::never();
}
}
alarm_timestamp().relax(sync_completed_at_);
alarm_timestamp().relax(update_certificate_at_);
}
void FullNodeShardImpl::start_up() {
auto X =
create_hash_tl_object<ton_api::tonNode_shardPublicOverlayId>(get_workchain(), get_shard(), zero_state_file_hash_);
td::BufferSlice b{32};
b.as_slice().copy_from(as_slice(X));
overlay_id_full_ = overlay::OverlayIdFull{std::move(b)};
overlay_id_ = overlay_id_full_.compute_short_id();
rules_ = overlay::OverlayPrivacyRules{overlay::Overlays::max_fec_broadcast_size()};
create_overlay();
}
void FullNodeShardImpl::sign_new_certificate(PublicKeyHash sign_by) {
if (sign_by.is_zero()) {
return;
}
ton::overlay::Certificate cert{sign_by, static_cast<td::int32>(td::Clocks::system() + 3600),
overlay::Overlays::max_fec_broadcast_size(), td::BufferSlice{}};
auto to_sign = cert.to_sign(overlay_id_, local_id_);
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), cert = std::move(cert)](td::Result<std::pair<td::BufferSlice, PublicKey>> R) mutable {
if (R.is_error()) {
// ignore
VLOG(FULL_NODE_WARNING) << "failed to create certificate: failed to sign: " << R.move_as_error();
} else {
auto p = R.move_as_ok();
cert.set_signature(std::move(p.first));
cert.set_issuer(p.second);
td::actor::send_closure(SelfId, &FullNodeShardImpl::signed_new_certificate, std::move(cert));
}
});
td::actor::send_closure(keyring_, &ton::keyring::Keyring::sign_add_get_public_key, sign_by, std::move(to_sign),
std::move(P));
}
void FullNodeShardImpl::signed_new_certificate(ton::overlay::Certificate cert) {
LOG(WARNING) << "updated certificate";
cert_ = std::make_shared<overlay::Certificate>(std::move(cert));
td::actor::send_closure(overlays_, &overlay::Overlays::update_certificate, adnl_id_, overlay_id_, local_id_, cert_);
}
void FullNodeShardImpl::update_validators(std::vector<PublicKeyHash> public_key_hashes, PublicKeyHash local_hash) {
bool update_cert = false;
if (!local_hash.is_zero() && local_hash != sign_cert_by_) {
update_cert = true;
}
sign_cert_by_ = local_hash;
std::map<PublicKeyHash, td::uint32> authorized_keys;
for (auto &key : public_key_hashes) {
authorized_keys.emplace(key, overlay::Overlays::max_fec_broadcast_size());
}
rules_ = overlay::OverlayPrivacyRules{overlay::Overlays::max_simple_broadcast_size(), std::move(authorized_keys)};
td::actor::send_closure(overlays_, &overlay::Overlays::set_privacy_rules, adnl_id_, overlay_id_, rules_);
if (update_cert) {
sign_new_certificate(sign_cert_by_);
update_certificate_at_ = td::Timestamp::in(30.0);
alarm_timestamp().relax(update_certificate_at_);
}
}
FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id,
FileHash zero_state_file_hash, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager)
: shard_(shard)
, local_id_(local_id)
, adnl_id_(adnl_id)
, zero_state_file_hash_(zero_state_file_hash)
, keyring_(keyring)
, adnl_(adnl)
, rldp_(rldp)
, overlays_(overlays)
, validator_manager_(validator_manager) {
}
td::actor::ActorOwn<FullNodeShard> FullNodeShard::create(
ShardIdFull shard, PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager) {
return td::actor::create_actor<FullNodeShardImpl>("tonnode", shard, local_id, adnl_id, zero_state_file_hash, keyring,
adnl, rldp, overlays, validator_manager);
}
} // namespace fullnode
} // namespace validator
} // namespace ton