1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-13 19:52:18 +00:00
ton/validator/full-node.cpp

897 lines
37 KiB
C++
Raw Normal View History

2019-09-07 10:03:22 +00:00
/*
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/>.
2020-04-10 19:06:01 +00:00
Copyright 2017-2020 Telegram Systems LLP
2019-09-07 10:03:22 +00:00
*/
#include "full-node.hpp"
#include "ton/ton-io.hpp"
#include "td/actor/MultiPromise.h"
#include "full-node.h"
2024-02-21 15:38:02 +00:00
#include "common/delay.h"
2019-09-07 10:03:22 +00:00
namespace ton {
namespace validator {
namespace fullnode {
static const double INACTIVE_SHARD_TTL = (double)overlay::Overlays::overlay_peer_ttl() + 60.0;
2022-07-29 07:39:02 +00:00
2019-09-07 10:03:22 +00:00
void FullNodeImpl::add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) {
if (local_keys_.count(key)) {
promise.set_value(td::Unit());
return;
}
local_keys_.insert(key);
create_private_block_overlay(key);
for (auto &p : custom_overlays_) {
update_custom_overlay(p.second);
}
2019-09-07 10:03:22 +00:00
if (!sign_cert_by_.is_zero()) {
promise.set_value(td::Unit());
return;
}
for (auto &x : all_validators_) {
if (x == key) {
sign_cert_by_ = key;
}
}
for (auto &shard : shards_) {
2022-07-29 07:39:02 +00:00
if (!shard.second.actor.empty()) {
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
}
2019-09-07 10:03:22 +00:00
}
promise.set_value(td::Unit());
}
void FullNodeImpl::del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) {
if (!local_keys_.count(key)) {
promise.set_value(td::Unit());
return;
}
local_keys_.erase(key);
private_block_overlays_.erase(key);
for (auto &p : custom_overlays_) {
update_custom_overlay(p.second);
}
2019-09-07 10:03:22 +00:00
if (sign_cert_by_ != key) {
promise.set_value(td::Unit());
return;
}
sign_cert_by_ = PublicKeyHash::zero();
for (auto &x : all_validators_) {
if (local_keys_.count(x)) {
sign_cert_by_ = x;
}
}
for (auto &shard : shards_) {
2022-07-29 07:39:02 +00:00
if (!shard.second.actor.empty()) {
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
}
2019-09-07 10:03:22 +00:00
}
promise.set_value(td::Unit());
}
2024-02-21 15:38:02 +00:00
void FullNodeImpl::add_collator_adnl_id(adnl::AdnlNodeIdShort id) {
++local_collator_nodes_[id];
}
void FullNodeImpl::del_collator_adnl_id(adnl::AdnlNodeIdShort id) {
if (--local_collator_nodes_[id] == 0) {
local_collator_nodes_.erase(id);
}
}
void FullNodeImpl::sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key, td::uint32 expiry_at,
td::uint32 max_size, td::Promise<td::BufferSlice> promise) {
2022-07-29 07:39:02 +00:00
auto it = shards_.find(shard_id);
if(it == shards_.end() || it->second.actor.empty()) {
promise.set_error(td::Status::Error(ErrorCode::error, "shard not found"));
return;
}
td::actor::send_closure(it->second.actor, &FullNodeShard::sign_overlay_certificate, signed_key, expiry_at, max_size,
std::move(promise));
}
void FullNodeImpl::import_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
std::shared_ptr<ton::overlay::Certificate> cert,
td::Promise<td::Unit> promise) {
2022-07-29 07:39:02 +00:00
auto it = shards_.find(shard_id);
if(it == shards_.end() || it->second.actor.empty()) {
promise.set_error(td::Status::Error(ErrorCode::error, "shard not found"));
return;
}
td::actor::send_closure(it->second.actor, &FullNodeShard::import_overlay_certificate, signed_key, cert,
std::move(promise));
}
2019-09-07 10:03:22 +00:00
void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) {
adnl_id_ = adnl_id;
td::MultiPromise mp;
auto ig = mp.init_guard();
ig.add_promise(std::move(promise));
for (auto &s : shards_) {
2022-07-29 07:39:02 +00:00
if (!s.second.actor.empty()) {
td::actor::send_closure(s.second.actor, &FullNodeShard::update_adnl_id, adnl_id, ig.get_promise());
}
2019-09-07 10:03:22 +00:00
}
local_id_ = adnl_id_.pubkey_hash();
for (auto &p : custom_overlays_) {
update_custom_overlay(p.second);
}
2019-09-07 10:03:22 +00:00
}
void FullNodeImpl::set_config(FullNodeConfig config) {
config_ = config;
for (auto& s : shards_) {
if (!s.second.actor.empty()) {
td::actor::send_closure(s.second.actor, &FullNodeShard::set_config, config);
}
}
for (auto& overlay : private_block_overlays_) {
td::actor::send_closure(overlay.second, &FullNodePrivateBlockOverlay::set_config, config);
}
for (auto& overlay : custom_overlays_) {
for (auto &actor : overlay.second.actors_) {
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::set_config, config);
}
}
}
void FullNodeImpl::add_custom_overlay(CustomOverlayParams params, td::Promise<td::Unit> promise) {
if (params.nodes_.empty()) {
promise.set_error(td::Status::Error("list of nodes is empty"));
return;
}
std::string name = params.name_;
if (custom_overlays_.count(name)) {
promise.set_error(td::Status::Error(PSTRING() << "duplicate custom overlay name \"" << name << "\""));
return;
}
VLOG(FULL_NODE_WARNING) << "Adding custom overlay \"" << name << "\", " << params.nodes_.size() << " nodes";
auto &p = custom_overlays_[name];
p.params_ = std::move(params);
update_custom_overlay(p);
promise.set_result(td::Unit());
}
void FullNodeImpl::del_custom_overlay(std::string name, td::Promise<td::Unit> promise) {
auto it = custom_overlays_.find(name);
if (it == custom_overlays_.end()) {
promise.set_error(td::Status::Error(PSTRING() << "no such overlay \"" << name << "\""));
return;
}
custom_overlays_.erase(it);
promise.set_result(td::Unit());
}
2019-09-07 10:03:22 +00:00
void FullNodeImpl::initial_read_complete(BlockHandle top_handle) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &FullNodeImpl::sync_completed);
});
auto it = shards_.find(ShardIdFull{masterchainId});
2022-07-29 07:39:02 +00:00
CHECK(it != shards_.end() && !it->second.actor.empty());
td::actor::send_closure(it->second.actor, &FullNodeShard::set_handle, top_handle, std::move(P));
2019-09-07 10:03:22 +00:00
}
void FullNodeImpl::on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards) {
CHECK(shards_to_monitor.count(ShardIdFull(masterchainId)));
2022-10-03 14:55:37 +00:00
std::set<ShardIdFull> new_shards;
std::map<ShardIdFull, FullNodeShardMode> new_active;
2022-10-03 14:55:37 +00:00
new_shards.insert(ShardIdFull(masterchainId));
2022-07-29 07:39:02 +00:00
std::set<WorkchainId> workchains;
2022-10-03 14:55:37 +00:00
auto cut_shard = [&](ShardIdFull shard) -> ShardIdFull {
int min_split = state->monitor_min_split_depth(shard.workchain);
2023-01-12 14:32:59 +00:00
return min_split < shard.pfx_len() ? shard_prefix(shard, min_split) : shard;
2022-10-03 14:55:37 +00:00
};
auto set_active = [&](ShardIdFull shard, FullNodeShardMode mode) {
while (new_active.emplace(shard, mode).second && shard.pfx_len() > 0) {
2022-07-29 07:39:02 +00:00
shard = shard_parent(shard);
}
};
for (auto &info : state->get_shards()) {
2022-08-03 12:15:42 +00:00
workchains.insert(info->shard().workchain);
2022-10-03 14:55:37 +00:00
new_shards.insert(cut_shard(info->shard()));
2022-07-29 07:39:02 +00:00
}
for (const auto &wpair : state->get_workchain_list()) {
ton::WorkchainId wc = wpair.first;
const block::WorkchainInfo *winfo = wpair.second.get();
2022-08-03 12:15:42 +00:00
if (workchains.count(wc) == 0 && winfo->active && winfo->enabled_since <= state->get_unix_time()) {
2022-10-03 14:55:37 +00:00
new_shards.insert(ShardIdFull(wc));
2022-07-29 07:39:02 +00:00
}
}
2022-08-03 12:15:42 +00:00
for (ShardIdFull shard : shards_to_monitor) {
2022-10-03 14:55:37 +00:00
set_active(cut_shard(shard), FullNodeShardMode::active);
}
for (ShardIdFull shard : temporary_shards) {
2022-10-03 14:55:37 +00:00
set_active(cut_shard(shard), FullNodeShardMode::active_temp);
2022-08-03 12:15:42 +00:00
}
2022-07-29 07:39:02 +00:00
auto info_set_mode = [&](ShardIdFull shard, ShardInfo &info, FullNodeShardMode mode) {
if (info.mode == mode) {
2022-07-29 07:39:02 +00:00
return;
}
if (info.actor.empty()) {
add_shard_actor(shard, mode);
2022-07-29 07:39:02 +00:00
return;
}
info.mode = mode;
td::actor::send_closure(info.actor, &FullNodeShard::set_mode, mode);
info.delete_at =
mode != FullNodeShardMode::inactive ? td::Timestamp::never() : td::Timestamp::in(INACTIVE_SHARD_TTL);
2022-07-29 07:39:02 +00:00
};
for (auto shard : new_shards) {
2022-10-03 14:55:37 +00:00
auto &info = shards_[shard];
2022-07-29 07:39:02 +00:00
info.exists = true;
}
for (auto &p : shards_) {
2022-07-29 07:39:02 +00:00
ShardIdFull shard = p.first;
ShardInfo &info = p.second;
info.exists = new_shards.count(shard);
auto it = new_active.find(shard);
info_set_mode(shard, info, it == new_active.end() ? FullNodeShardMode::inactive : it->second);
2022-07-29 07:39:02 +00:00
}
for (const auto &s : new_active) {
info_set_mode(s.first, shards_[s.first], s.second);
2022-07-29 07:39:02 +00:00
}
auto it = shards_.begin();
while (it != shards_.end()) {
if (it->second.mode == FullNodeShardMode::inactive && it->second.delete_at && it->second.delete_at.is_in_past()) {
2022-07-29 07:39:02 +00:00
it->second.actor.reset();
it->second.delete_at = td::Timestamp::never();
}
if (!it->second.exists && it->second.actor.empty()) {
it = shards_.erase(it);
} else {
++it;
2019-09-07 10:03:22 +00:00
}
}
2024-02-21 15:38:02 +00:00
if (!use_old_private_overlays_) {
std::set<adnl::AdnlNodeIdShort> my_adnl_ids;
my_adnl_ids.insert(adnl_id_);
for (const auto &p : local_collator_nodes_) {
my_adnl_ids.insert(p.first);
2024-02-21 15:38:02 +00:00
}
for (auto key : local_keys_) {
auto it = current_validators_.find(key);
if (it != current_validators_.end()) {
my_adnl_ids.insert(it->second);
}
}
std::set<ShardIdFull> monitoring_shards;
for (ShardIdFull shard : shards_to_monitor) {
monitoring_shards.insert(cut_shard(shard));
}
fast_sync_overlays_.update_overlays(state, std::move(my_adnl_ids), std::move(monitoring_shards),
zero_state_file_hash_, keyring_, adnl_, overlays_, validator_manager_,
actor_id(this));
}
2019-09-07 10:03:22 +00:00
}
void FullNodeImpl::add_shard_actor(ShardIdFull shard, FullNodeShardMode mode) {
2022-07-29 07:39:02 +00:00
ShardInfo &info = shards_[shard];
if (!info.actor.empty()) {
return;
}
info.actor = FullNodeShard::create(shard, local_id_, adnl_id_, zero_state_file_hash_, config_, keyring_, adnl_, rldp_,
rldp2_, overlays_, validator_manager_, client_, actor_id(this), mode);
info.mode = mode;
info.delete_at = mode != FullNodeShardMode::inactive ? td::Timestamp::never() : td::Timestamp::in(INACTIVE_SHARD_TTL);
2022-07-29 07:39:02 +00:00
if (all_validators_.size() > 0) {
td::actor::send_closure(info.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
}
2019-09-07 10:03:22 +00:00
}
void FullNodeImpl::sync_completed() {
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::sync_complete, [](td::Unit) {});
}
void FullNodeImpl::send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) {
auto shard = get_shard(dst);
2019-09-07 10:03:22 +00:00
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping OUT ihr message to unknown shard";
return;
}
td::actor::send_closure(shard, &FullNodeShard::send_ihr_message, std::move(data));
}
void FullNodeImpl::send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data) {
auto shard = get_shard(dst);
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping OUT ext message to unknown shard";
return;
}
for (auto &private_overlay : custom_overlays_) {
for (auto &actor : private_overlay.second.actors_) {
auto local_id = actor.first;
if (private_overlay.second.params_.msg_senders_.count(local_id)) {
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_external_message, data.clone());
}
}
}
2019-09-07 10:03:22 +00:00
td::actor::send_closure(shard, &FullNodeShard::send_external_message, std::move(data));
}
void FullNodeImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
2022-07-29 07:39:02 +00:00
auto shard = get_shard(ShardIdFull{masterchainId});
2019-09-07 10:03:22 +00:00
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping OUT shard block info message to unknown shard";
return;
}
if (!private_block_overlays_.empty()) {
td::actor::send_closure(private_block_overlays_.begin()->second,
&FullNodePrivateBlockOverlay::send_shard_block_info, block_id, cc_seqno, data.clone());
}
auto fast_sync_overlay = fast_sync_overlays_.choose_overlay(ShardIdFull(masterchainId));
if (!fast_sync_overlay.empty()) {
td::actor::send_closure(fast_sync_overlay, &FullNodeFastSyncOverlay::send_shard_block_info, block_id, cc_seqno,
2024-02-21 15:38:02 +00:00
data.clone());
}
2019-09-07 10:03:22 +00:00
td::actor::send_closure(shard, &FullNodeShard::send_shard_block_info, block_id, cc_seqno, std::move(data));
}
void FullNodeImpl::send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
td::BufferSlice data) {
send_block_candidate_broadcast_to_custom_overlays(block_id, cc_seqno, validator_set_hash, data);
auto shard = get_shard(ShardIdFull{masterchainId, shardIdAll});
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping OUT shard block info message to unknown shard";
return;
}
if (!private_block_overlays_.empty()) {
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_block_candidate,
block_id, cc_seqno, validator_set_hash, data.clone());
}
auto fast_sync_overlay = fast_sync_overlays_.choose_overlay(block_id.shard_full());
if (!fast_sync_overlay.empty()) {
td::actor::send_closure(fast_sync_overlay, &FullNodeFastSyncOverlay::send_block_candidate, block_id, cc_seqno,
validator_set_hash, data.clone());
}
if (broadcast_block_candidates_in_public_overlay_) {
td::actor::send_closure(shard, &FullNodeShard::send_block_candidate, block_id, cc_seqno, validator_set_hash,
std::move(data));
}
}
void FullNodeImpl::send_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) {
send_block_broadcast_to_custom_overlays(broadcast);
if (custom_overlays_only) {
return;
}
2022-10-03 14:55:37 +00:00
auto shard = get_shard(broadcast.block_id.shard_full());
2019-09-07 10:03:22 +00:00
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping OUT broadcast to unknown shard";
return;
}
if (broadcast.block_id.is_masterchain()) {
if (!private_block_overlays_.empty()) {
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_broadcast,
broadcast.clone());
}
auto fast_sync_overlay = fast_sync_overlays_.choose_overlay(broadcast.block_id.shard_full());
if (!fast_sync_overlay.empty()) {
td::actor::send_closure(fast_sync_overlay, &FullNodeFastSyncOverlay::send_broadcast, broadcast.clone());
}
}
2019-09-07 10:03:22 +00:00
td::actor::send_closure(shard, &FullNodeShard::send_broadcast, std::move(broadcast));
}
void FullNodeImpl::download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<ReceivedBlock> promise) {
auto shard = get_shard(id.shard_full());
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping download block query to unknown shard";
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
return;
}
td::actor::send_closure(shard, &FullNodeShard::download_block, id, priority, timeout, std::move(promise));
}
void FullNodeImpl::download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
auto shard = get_shard(id.shard_full());
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping download state query to unknown shard";
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
return;
}
td::actor::send_closure(shard, &FullNodeShard::download_zero_state, id, priority, timeout, std::move(promise));
}
void FullNodeImpl::download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) {
auto shard = get_shard(id.shard_full());
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping download state diff query to unknown shard";
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
return;
}
td::actor::send_closure(shard, &FullNodeShard::download_persistent_state, id, masterchain_block_id, priority, timeout,
std::move(promise));
}
void FullNodeImpl::download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
auto shard = get_shard(block_id.shard_full());
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping download proof query to unknown shard";
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
return;
}
td::actor::send_closure(shard, &FullNodeShard::download_block_proof, block_id, priority, timeout, std::move(promise));
}
void FullNodeImpl::download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) {
auto shard = get_shard(block_id.shard_full());
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping download proof link query to unknown shard";
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
return;
}
td::actor::send_closure(shard, &FullNodeShard::download_block_proof_link, block_id, priority, timeout,
std::move(promise));
}
void FullNodeImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
td::Promise<std::vector<BlockIdExt>> promise) {
auto shard = get_shard(block_id.shard_full());
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping download proof link query to unknown shard";
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
return;
}
td::actor::send_closure(shard, &FullNodeShard::get_next_key_blocks, block_id, timeout, std::move(promise));
}
void FullNodeImpl::download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) {
auto shard = get_shard(shard_prefix);
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping download archive query to unknown shard";
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
return;
}
2019-11-15 14:02:37 +00:00
CHECK(!shard.empty());
td::actor::send_closure(shard, &FullNodeShard::download_archive, masterchain_seqno, shard_prefix, std::move(tmp_dir),
timeout, std::move(promise));
2019-11-15 14:02:37 +00:00
}
2023-07-31 15:12:09 +00:00
void FullNodeImpl::download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
2023-07-24 12:29:55 +00:00
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
2023-07-31 15:12:09 +00:00
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) {
if (blocks.empty()) {
promise.set_value({});
return;
}
// All blocks are expected to have the same minsplit shard prefix
auto shard = get_shard(blocks[0].shard_full());
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping download msg queue query to unknown shard";
promise.set_error(td::Status::Error(ErrorCode::notready, "shard not ready"));
return;
}
2023-07-31 15:12:09 +00:00
td::actor::send_closure(shard, &FullNodeShard::download_out_msg_queue_proof, dst_shard, std::move(blocks), limits,
timeout, std::move(promise));
}
2022-10-03 14:55:37 +00:00
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(ShardIdFull shard) {
2023-01-12 14:32:59 +00:00
ShardIdFull shard0 = shard;
2022-10-03 14:55:37 +00:00
while (true) {
auto it = shards_.find(shard);
if (it != shards_.end() && it->second.exists) {
if (it->second.actor.empty()) {
add_shard_actor(shard, FullNodeShardMode::inactive);
2022-07-29 07:39:02 +00:00
}
2022-10-03 14:55:37 +00:00
if (it->second.mode == FullNodeShardMode::inactive) {
it->second.delete_at = td::Timestamp::in(INACTIVE_SHARD_TTL);
2022-07-29 07:39:02 +00:00
}
2022-10-03 14:55:37 +00:00
return it->second.actor.get();
2019-09-07 10:03:22 +00:00
}
2022-10-03 14:55:37 +00:00
if (shard.pfx_len() == 0) {
break;
}
shard = shard_parent(shard);
}
2023-01-12 14:32:59 +00:00
shard = shard0;
2022-10-03 14:55:37 +00:00
auto it = shards_.find(shard);
if (it == shards_.end()) {
it = shards_.emplace(shard = ShardIdFull(shard.workchain), ShardInfo{}).first;
2019-09-07 10:03:22 +00:00
}
2022-10-03 14:55:37 +00:00
auto &info = it->second;
2022-07-29 07:39:02 +00:00
if (info.actor.empty()) {
add_shard_actor(shard, FullNodeShardMode::inactive);
2022-07-29 07:39:02 +00:00
}
if (info.mode == FullNodeShardMode::inactive) {
2022-07-29 07:39:02 +00:00
info.delete_at = td::Timestamp::in(INACTIVE_SHARD_TTL);
}
return info.actor.get();
2019-09-07 10:03:22 +00:00
}
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(AccountIdPrefixFull dst) {
2022-07-29 07:39:02 +00:00
return get_shard(shard_prefix(dst, max_shard_pfx_len));
2019-09-07 10:03:22 +00:00
}
void FullNodeImpl::got_key_block_config(td::Ref<ConfigHolder> config) {
2019-09-07 10:03:22 +00:00
PublicKeyHash l = PublicKeyHash::zero();
std::vector<PublicKeyHash> keys;
std::map<PublicKeyHash, adnl::AdnlNodeIdShort> current_validators;
2019-09-07 10:03:22 +00:00
for (td::int32 i = -1; i <= 1; i++) {
auto r = config->get_total_validator_set(i < 0 ? i : 1 - i);
2019-09-07 10:03:22 +00:00
if (r.not_null()) {
auto vec = r->export_vector();
for (auto &el : vec) {
auto key = ValidatorFullId{el.key}.compute_short_id();
keys.push_back(key);
if (local_keys_.count(key)) {
l = key;
}
if (i == 1) {
current_validators[key] = adnl::AdnlNodeIdShort{el.addr.is_zero() ? key.bits256_value() : el.addr};
}
2019-09-07 10:03:22 +00:00
}
}
}
if (current_validators != current_validators_) {
current_validators_ = std::move(current_validators);
update_private_overlays();
}
2024-06-04 10:09:06 +00:00
// Let's turn off this optimization, since keyblocks are rare enough to update on each keyblock
// if (keys == all_validators_) {
// return;
// }
2019-09-07 10:03:22 +00:00
all_validators_ = keys;
sign_cert_by_ = l;
CHECK(all_validators_.size() > 0);
for (auto &shard : shards_) {
2022-07-29 07:39:02 +00:00
if (!shard.second.actor.empty()) {
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
}
2019-09-07 10:03:22 +00:00
}
}
void FullNodeImpl::new_key_block(BlockHandle handle) {
if (handle->id().seqno() == 0) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) {
VLOG(FULL_NODE_WARNING) << "failed to get zero state: " << R.move_as_error();
} else {
auto s = td::Ref<MasterchainState>{R.move_as_ok()};
CHECK(s.not_null());
td::actor::send_closure(SelfId, &FullNodeImpl::got_key_block_config, s->get_config_holder().move_as_ok());
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_shard_state_from_db, handle,
std::move(P));
} else {
CHECK(handle->is_key_block());
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ProofLink>> R) {
if (R.is_error()) {
VLOG(FULL_NODE_WARNING) << "failed to get key block proof: " << R.move_as_error();
} else {
td::actor::send_closure(SelfId, &FullNodeImpl::got_key_block_config,
R.ok()->get_key_block_config().move_as_ok());
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_block_proof_link_from_db, handle,
std::move(P));
}
2019-09-07 10:03:22 +00:00
}
void FullNodeImpl::process_block_broadcast(BlockBroadcast broadcast) {
send_block_broadcast_to_custom_overlays(broadcast);
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::prevalidate_block, std::move(broadcast),
[](td::Result<td::Unit> R) {
if (R.is_error()) {
if (R.error().code() == ErrorCode::notready) {
LOG(DEBUG) << "dropped broadcast: " << R.move_as_error();
} else {
LOG(INFO) << "dropped broadcast: " << R.move_as_error();
}
}
});
}
void FullNodeImpl::process_block_candidate_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno,
td::uint32 validator_set_hash, td::BufferSlice data) {
send_block_candidate_broadcast_to_custom_overlays(block_id, cc_seqno, validator_set_hash, data);
// ignore cc_seqno and validator_hash for now
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::new_block_candidate, block_id,
std::move(data));
}
2019-09-07 10:03:22 +00:00
void FullNodeImpl::start_up() {
add_shard_actor(ShardIdFull{masterchainId}, FullNodeShardMode::active);
2019-09-07 10:03:22 +00:00
if (local_id_.is_zero()) {
if (adnl_id_.is_zero()) {
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
local_id_ = pk.compute_short_id();
2019-09-07 10:03:22 +00:00
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {});
} else {
local_id_ = adnl_id_.pubkey_hash();
}
2019-09-07 10:03:22 +00:00
}
class Callback : public ValidatorManagerInterface::Callback {
public:
void initial_read_complete(BlockHandle handle) override {
td::actor::send_closure(id_, &FullNodeImpl::initial_read_complete, handle);
}
void on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor,
std::set<ShardIdFull> temporary_shards) override {
td::actor::send_closure(id_, &FullNodeImpl::on_new_masterchain_block, std::move(state),
std::move(shards_to_monitor), std::move(temporary_shards));
2019-09-07 10:03:22 +00:00
}
void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) override {
td::actor::send_closure(id_, &FullNodeImpl::send_ihr_message, dst, std::move(data));
}
void send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data) override {
td::actor::send_closure(id_, &FullNodeImpl::send_ext_message, dst, std::move(data));
}
void send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override {
td::actor::send_closure(id_, &FullNodeImpl::send_shard_block_info, block_id, cc_seqno, std::move(data));
}
void send_block_candidate(BlockIdExt block_id, CatchainSeqno cc_seqno, td::uint32 validator_set_hash,
td::BufferSlice data) override {
td::actor::send_closure(id_, &FullNodeImpl::send_block_candidate, block_id, cc_seqno, validator_set_hash,
std::move(data));
}
void send_broadcast(BlockBroadcast broadcast, bool custom_overlays_only) override {
td::actor::send_closure(id_, &FullNodeImpl::send_broadcast, std::move(broadcast), custom_overlays_only);
2019-09-07 10:03:22 +00:00
}
void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<ReceivedBlock> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::download_block, id, priority, timeout, std::move(promise));
}
void download_zero_state(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::download_zero_state, id, priority, timeout, std::move(promise));
}
void download_persistent_state(BlockIdExt id, BlockIdExt masterchain_block_id, td::uint32 priority,
td::Timestamp timeout, td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::download_persistent_state, id, masterchain_block_id, priority,
timeout, std::move(promise));
}
void download_block_proof(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::download_block_proof, block_id, priority, timeout,
std::move(promise));
}
void download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::download_block_proof_link, block_id, priority, timeout,
std::move(promise));
}
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
td::Promise<std::vector<BlockIdExt>> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::get_next_key_blocks, block_id, timeout, std::move(promise));
}
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::download_archive, masterchain_seqno, shard_prefix, std::move(tmp_dir),
timeout, std::move(promise));
2019-11-15 14:02:37 +00:00
}
2023-07-31 15:12:09 +00:00
void download_out_msg_queue_proof(ShardIdFull dst_shard, std::vector<BlockIdExt> blocks,
block::ImportedMsgQueueLimits limits, td::Timestamp timeout,
td::Promise<std::vector<td::Ref<OutMsgQueueProof>>> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::download_out_msg_queue_proof, dst_shard, std::move(blocks), limits,
timeout, std::move(promise));
}
2019-09-07 10:03:22 +00:00
void new_key_block(BlockHandle handle) override {
td::actor::send_closure(id_, &FullNodeImpl::new_key_block, std::move(handle));
}
Callback(td::actor::ActorId<FullNodeImpl> id) : id_(id) {
}
private:
td::actor::ActorId<FullNodeImpl> id_;
};
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::install_callback,
2022-07-29 07:39:02 +00:00
std::make_unique<Callback>(actor_id(this)), std::move(started_promise_));
2019-09-07 10:03:22 +00:00
}
void FullNodeImpl::update_private_overlays() {
for (auto &p : custom_overlays_) {
update_custom_overlay(p.second);
}
private_block_overlays_.clear();
if (local_keys_.empty()) {
return;
}
for (const auto &key : local_keys_) {
create_private_block_overlay(key);
}
}
void FullNodeImpl::create_private_block_overlay(PublicKeyHash key) {
if (!use_old_private_overlays_) {
return;
}
2024-02-21 15:38:02 +00:00
CHECK(local_keys_.count(key));
if (current_validators_.count(key)) {
std::vector<adnl::AdnlNodeIdShort> nodes;
for (const auto &p : current_validators_) {
nodes.push_back(p.second);
}
private_block_overlays_[key] = td::actor::create_actor<FullNodePrivateBlockOverlay>(
"BlocksPrivateOverlay", current_validators_[key], std::move(nodes), zero_state_file_hash_, config_, keyring_,
adnl_, rldp_, rldp2_, overlays_, validator_manager_, actor_id(this));
2024-02-21 15:38:02 +00:00
}
}
void FullNodeImpl::update_custom_overlay(CustomOverlayInfo &overlay) {
auto old_actors = std::move(overlay.actors_);
overlay.actors_.clear();
CustomOverlayParams &params = overlay.params_;
auto try_local_id = [&](const adnl::AdnlNodeIdShort &local_id) {
if (std::find(params.nodes_.begin(), params.nodes_.end(), local_id) != params.nodes_.end()) {
auto it = old_actors.find(local_id);
if (it != old_actors.end()) {
overlay.actors_[local_id] = std::move(it->second);
old_actors.erase(it);
} else {
overlay.actors_[local_id] = td::actor::create_actor<FullNodeCustomOverlay>(
"CustomOverlay", local_id, params, zero_state_file_hash_, config_, keyring_, adnl_, rldp_, rldp2_,
overlays_, validator_manager_, actor_id(this));
}
}
};
try_local_id(adnl_id_);
for (const PublicKeyHash &local_key : local_keys_) {
auto it = current_validators_.find(local_key);
if (it != current_validators_.end()) {
try_local_id(it->second);
}
}
}
void FullNodeImpl::send_block_broadcast_to_custom_overlays(const BlockBroadcast& broadcast) {
if (!custom_overlays_sent_broadcasts_.insert(broadcast.block_id).second) {
return;
}
custom_overlays_sent_broadcasts_lru_.push(broadcast.block_id);
if (custom_overlays_sent_broadcasts_lru_.size() > 256) {
custom_overlays_sent_broadcasts_.erase(custom_overlays_sent_broadcasts_lru_.front());
custom_overlays_sent_broadcasts_lru_.pop();
}
for (auto &private_overlay : custom_overlays_) {
for (auto &actor : private_overlay.second.actors_) {
auto local_id = actor.first;
if (private_overlay.second.params_.block_senders_.count(local_id)) {
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_broadcast, broadcast.clone());
}
}
}
}
void FullNodeImpl::send_block_candidate_broadcast_to_custom_overlays(const BlockIdExt &block_id, CatchainSeqno cc_seqno,
td::uint32 validator_set_hash,
const td::BufferSlice &data) {
// Same cache of sent broadcasts as in send_block_broadcast_to_custom_overlays
if (!custom_overlays_sent_broadcasts_.insert(block_id).second) {
return;
}
custom_overlays_sent_broadcasts_lru_.push(block_id);
if (custom_overlays_sent_broadcasts_lru_.size() > 256) {
custom_overlays_sent_broadcasts_.erase(custom_overlays_sent_broadcasts_lru_.front());
custom_overlays_sent_broadcasts_lru_.pop();
}
for (auto &private_overlay : custom_overlays_) {
for (auto &actor : private_overlay.second.actors_) {
auto local_id = actor.first;
if (private_overlay.second.params_.block_senders_.count(local_id)) {
td::actor::send_closure(actor.second, &FullNodeCustomOverlay::send_block_candidate, block_id, cc_seqno,
validator_set_hash, data.clone());
}
}
}
}
2019-09-07 10:03:22 +00:00
FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash,
FullNodeConfig config, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<dht::Dht> dht,
2022-08-03 12:15:42 +00:00
td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
2022-07-29 07:39:02 +00:00
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root,
td::Promise<td::Unit> started_promise)
2019-09-07 10:03:22 +00:00
: local_id_(local_id)
, adnl_id_(adnl_id)
, zero_state_file_hash_(zero_state_file_hash)
, keyring_(keyring)
, adnl_(adnl)
, rldp_(rldp)
, rldp2_(rldp2)
2019-09-07 10:03:22 +00:00
, dht_(dht)
, overlays_(overlays)
, validator_manager_(validator_manager)
, client_(client)
2022-07-29 07:39:02 +00:00
, db_root_(db_root)
, started_promise_(std::move(started_promise))
, config_(config) {
2019-09-07 10:03:22 +00:00
}
2022-08-03 12:15:42 +00:00
td::actor::ActorOwn<FullNode> FullNode::create(
ton::PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id, FileHash zero_state_file_hash, FullNodeConfig config,
2022-08-03 12:15:42 +00:00
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<dht::Dht> dht,
2022-08-03 12:15:42 +00:00
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root, td::Promise<td::Unit> started_promise) {
return td::actor::create_actor<FullNodeImpl>("fullnode", local_id, adnl_id, zero_state_file_hash, config, keyring,
adnl, rldp, rldp2, dht, overlays, validator_manager, client, db_root,
2022-07-29 07:39:02 +00:00
std::move(started_promise));
2019-09-07 10:03:22 +00:00
}
FullNodeConfig::FullNodeConfig(const tl_object_ptr<ton_api::engine_validator_fullNodeConfig> &obj)
: ext_messages_broadcast_disabled_(obj->ext_messages_broadcast_disabled_) {
}
tl_object_ptr<ton_api::engine_validator_fullNodeConfig> FullNodeConfig::tl() const {
return create_tl_object<ton_api::engine_validator_fullNodeConfig>(ext_messages_broadcast_disabled_);
}
bool FullNodeConfig::operator==(const FullNodeConfig &rhs) const {
return ext_messages_broadcast_disabled_ == rhs.ext_messages_broadcast_disabled_;
}
bool FullNodeConfig::operator!=(const FullNodeConfig &rhs) const {
return !(*this == rhs);
2019-09-07 10:03:22 +00:00
}
CustomOverlayParams CustomOverlayParams::fetch(const ton_api::engine_validator_customOverlay& f) {
CustomOverlayParams c;
c.name_ = f.name_;
for (const auto &node : f.nodes_) {
c.nodes_.emplace_back(node->adnl_id_);
if (node->msg_sender_) {
c.msg_senders_[ton::adnl::AdnlNodeIdShort{node->adnl_id_}] = node->msg_sender_priority_;
}
if (node->block_sender_) {
c.block_senders_.emplace(node->adnl_id_);
}
}
return c;
}
2019-09-07 10:03:22 +00:00
} // namespace fullnode
} // namespace validator
} // namespace ton