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

Accelerator: partial fullnodes (#1393)

* Accelerator: partial fullnodes

1) Node can monitor a subset of shards
2) New archive slice format (sharded)
3) Validators are still required to have all shards
4) Support partial liteservers in lite-client, blockchain explorer, tonlib
5) Proxy liteserver

* Fix compilation error
This commit is contained in:
SpyCheese 2024-11-26 15:46:58 +04:00 committed by GitHub
parent 62444100f5
commit 954a96a077
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
83 changed files with 3213 additions and 1113 deletions

View file

@ -624,7 +624,7 @@ void ArchiveManager::load_package(PackageId id) {
}
}
desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.id, id.key, id.temp, false, db_root_,
desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.id, id.key, id.temp, false, 0, db_root_,
archive_lru_.get(), statistics_);
m.emplace(id, std::move(desc));
@ -659,7 +659,8 @@ const ArchiveManager::FileDescription *ArchiveManager::add_file_desc(ShardIdFull
FileDescription new_desc{id, false};
td::mkdir(db_root_ + id.path()).ensure();
std::string prefix = PSTRING() << db_root_ << id.path() << id.name();
new_desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.id, id.key, id.temp, false, db_root_,
new_desc.file = td::actor::create_actor<ArchiveSlice>("slice", id.id, id.key, id.temp, false,
id.key || id.temp ? 0 : cur_shard_split_depth_, db_root_,
archive_lru_.get(), statistics_);
const FileDescription &desc = f.emplace(id, std::move(new_desc));
if (!id.temp) {
@ -1132,14 +1133,16 @@ PackageId ArchiveManager::get_package_id_force(BlockSeqno masterchain_seqno, Sha
return it->first;
}
void ArchiveManager::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) {
void ArchiveManager::get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
td::Promise<td::uint64> promise) {
auto F = get_file_desc_by_seqno(ShardIdFull{masterchainId}, masterchain_seqno, false);
if (!F) {
promise.set_error(td::Status::Error(ErrorCode::notready, "archive not found"));
return;
}
td::actor::send_closure(F->file_actor_id(), &ArchiveSlice::get_archive_id, masterchain_seqno, std::move(promise));
td::actor::send_closure(F->file_actor_id(), &ArchiveSlice::get_archive_id, masterchain_seqno, shard_prefix,
std::move(promise));
}
void ArchiveManager::get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,

View file

@ -67,7 +67,7 @@ class ArchiveManager : public td::actor::Actor {
void get_block_by_lt(AccountIdPrefixFull account_id, LogicalTime lt, td::Promise<ConstBlockHandle> promise);
void get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<ConstBlockHandle> promise);
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise);
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise);
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
td::Promise<td::BufferSlice> promise);
@ -77,6 +77,10 @@ class ArchiveManager : public td::actor::Actor {
void commit_transaction();
void set_async_mode(bool mode, td::Promise<td::Unit> promise);
void set_current_shard_split_depth(td::uint32 value) {
cur_shard_split_depth_ = value;
}
static constexpr td::uint32 archive_size() {
return 20000;
}
@ -175,6 +179,7 @@ class ArchiveManager : public td::actor::Actor {
bool async_mode_ = false;
bool huge_transaction_started_ = false;
td::uint32 huge_transaction_size_ = 0;
td::uint32 cur_shard_split_depth_ = 0;
DbStatistics statistics_;

View file

@ -39,7 +39,7 @@ class PackageStatistics {
void record_close(uint64_t count = 1) {
close_count.fetch_add(count, std::memory_order_relaxed);
}
void record_read(double time, uint64_t bytes) {
read_bytes.fetch_add(bytes, std::memory_order_relaxed);
std::lock_guard guard(read_mutex);
@ -56,10 +56,10 @@ class PackageStatistics {
std::stringstream ss;
ss.setf(std::ios::fixed);
ss.precision(6);
ss << "ton.pack.open COUNT : " << open_count.exchange(0, std::memory_order_relaxed) << "\n";
ss << "ton.pack.close COUNT : " << close_count.exchange(0, std::memory_order_relaxed) << "\n";
ss << "ton.pack.read.bytes COUNT : " << read_bytes.exchange(0, std::memory_order_relaxed) << "\n";
ss << "ton.pack.write.bytes COUNT : " << write_bytes.exchange(0, std::memory_order_relaxed) << "\n";
@ -118,7 +118,7 @@ void PackageWriter::append(std::string filename, td::BufferSlice data,
return;
}
start = td::Timestamp::now();
offset = p->append(std::move(filename), std::move(data), !async_mode_);
offset = p->append(std::move(filename), std::move(data), !async_mode_);
end = td::Timestamp::now();
size = p->size();
}
@ -152,6 +152,21 @@ class PackageReader : public td::actor::Actor {
std::shared_ptr<PackageStatistics> statistics_;
};
static std::string get_package_file_name(PackageId p_id, ShardIdFull shard_prefix) {
td::StringBuilder sb;
sb << p_id.name();
if (!shard_prefix.is_masterchain()) {
sb << ".";
sb << shard_prefix.workchain << ":" << shard_to_str(shard_prefix.shard);
}
sb << ".pack";
return sb.as_cslice().str();
}
static std::string package_info_to_str(BlockSeqno seqno, ShardIdFull shard_prefix) {
return PSTRING() << seqno << "." << shard_prefix.workchain << ":" << shard_to_str(shard_prefix.shard);
}
void ArchiveSlice::add_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
if (destroyed_) {
promise.set_error(td::Status::Error(ErrorCode::notready, "package already gc'd"));
@ -271,7 +286,8 @@ void ArchiveSlice::add_file(BlockHandle handle, FileReference ref_id, td::Buffer
TRY_RESULT_PROMISE(
promise, p,
choose_package(
handle ? handle->id().is_masterchain() ? handle->id().seqno() : handle->masterchain_ref_block() : 0, true));
handle ? handle->id().is_masterchain() ? handle->id().seqno() : handle->masterchain_ref_block() : 0,
handle ? handle->id().shard_full() : ShardIdFull{masterchainId}, true));
std::string value;
auto R = kv_->get(ref_id.hash().to_hex(), value);
R.ensure();
@ -376,7 +392,8 @@ void ArchiveSlice::get_file(ConstBlockHandle handle, FileReference ref_id, td::P
TRY_RESULT_PROMISE(
promise, p,
choose_package(
handle ? handle->id().is_masterchain() ? handle->id().seqno() : handle->masterchain_ref_block() : 0, false));
handle ? handle->id().is_masterchain() ? handle->id().seqno() : handle->masterchain_ref_block() : 0,
handle ? handle->id().shard_full() : ShardIdFull{masterchainId}, false));
promise = begin_async_query(std::move(promise));
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise)](td::Result<std::pair<std::string, td::BufferSlice>> R) mutable {
@ -536,18 +553,32 @@ void ArchiveSlice::get_slice(td::uint64 archive_id, td::uint64 offset, td::uint3
}
before_query();
auto value = static_cast<td::uint32>(archive_id >> 32);
TRY_RESULT_PROMISE(promise, p, choose_package(value, false));
PackageInfo *p;
if (shard_split_depth_ == 0) {
TRY_RESULT_PROMISE_ASSIGN(promise, p, choose_package(value, ShardIdFull{masterchainId}, false));
} else {
if (value >= packages_.size()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "no such package"));
return;
}
p = &packages_[value];
}
promise = begin_async_query(std::move(promise));
td::actor::create_actor<db::ReadFile>("readfile", p->path, offset, limit, 0, std::move(promise)).release();
}
void ArchiveSlice::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) {
void ArchiveSlice::get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
td::Promise<td::uint64> promise) {
before_query();
if (!sliced_mode_) {
promise.set_result(archive_id_);
} else {
TRY_RESULT_PROMISE(promise, p, choose_package(masterchain_seqno, false));
promise.set_result(p->id * (1ull << 32) + archive_id_);
TRY_RESULT_PROMISE(promise, p, choose_package(masterchain_seqno, shard_prefix, false));
if (shard_split_depth_ == 0) {
promise.set_result(p->seqno * (1ull << 32) + archive_id_);
} else {
promise.set_result(p->idx * (1ull << 32) + archive_id_);
}
}
}
@ -573,9 +604,18 @@ void ArchiveSlice::before_query() {
R2.ensure();
slice_size_ = td::to_integer<td::uint32>(value);
CHECK(slice_size_ > 0);
R2 = kv_->get("shard_split_depth", value);
R2.ensure();
if (R2.move_as_ok() == td::KeyValue::GetStatus::Ok) {
shard_split_depth_ = td::to_integer<td::uint32>(value);
CHECK(shard_split_depth_ <= 60);
} else {
shard_split_depth_ = 0;
}
for (td::uint32 i = 0; i < tot; i++) {
R2 = kv_->get(PSTRING() << "status." << i, value);
R2.ensure();
CHECK(R2.move_as_ok() == td::KeyValue::GetStatus::Ok);
auto len = td::to_integer<td::uint64>(value);
R2 = kv_->get(PSTRING() << "version." << i, value);
R2.ensure();
@ -583,12 +623,24 @@ void ArchiveSlice::before_query() {
if (R2.move_as_ok() == td::KeyValue::GetStatus::Ok) {
ver = td::to_integer<td::uint32>(value);
}
auto v = archive_id_ + slice_size_ * i;
add_package(v, len, ver);
td::uint32 seqno;
ShardIdFull shard_prefix;
if (shard_split_depth_ == 0) {
seqno = archive_id_ + slice_size_ * i;
shard_prefix = ShardIdFull{masterchainId};
} else {
R2 = kv_->get(PSTRING() << "info." << i, value);
R2.ensure();
CHECK(R2.move_as_ok() == td::KeyValue::GetStatus::Ok);
unsigned long long shard;
CHECK(sscanf(value.c_str(), "%u.%d:%016llx", &seqno, &shard_prefix.workchain, &shard) == 3);
shard_prefix.shard = shard;
}
add_package(seqno, shard_prefix, len, ver);
}
} else {
auto len = td::to_integer<td::uint64>(value);
add_package(archive_id_, len, 0);
add_package(archive_id_, ShardIdFull{masterchainId}, len, 0);
}
} else {
if (!temp_ && !key_blocks_only_) {
@ -599,13 +651,17 @@ void ArchiveSlice::before_query() {
kv_->set("slice_size", td::to_string(slice_size_)).ensure();
kv_->set("status.0", "0").ensure();
kv_->set("version.0", td::to_string(default_package_version())).ensure();
if (shard_split_depth_ > 0) {
kv_->set("info.0", package_info_to_str(archive_id_, ShardIdFull{masterchainId})).ensure();
kv_->set("shard_split_depth", td::to_string(shard_split_depth_)).ensure();
}
kv_->commit_transaction().ensure();
add_package(archive_id_, 0, default_package_version());
add_package(archive_id_, ShardIdFull{masterchainId}, 0, default_package_version());
} else {
kv_->begin_transaction().ensure();
kv_->set("status", "0").ensure();
kv_->commit_transaction().ensure();
add_package(archive_id_, 0, 0);
add_package(archive_id_, ShardIdFull{masterchainId}, 0, 0);
}
}
}
@ -642,6 +698,7 @@ void ArchiveSlice::do_close() {
statistics_.pack_statistics->record_close(packages_.size());
}
packages_.clear();
id_to_package_.clear();
}
template<typename T>
@ -697,48 +754,61 @@ void ArchiveSlice::set_async_mode(bool mode, td::Promise<td::Unit> promise) {
}
}
ArchiveSlice::ArchiveSlice(td::uint32 archive_id, bool key_blocks_only, bool temp, bool finalized, std::string db_root,
ArchiveSlice::ArchiveSlice(td::uint32 archive_id, bool key_blocks_only, bool temp, bool finalized,
td::uint32 shard_split_depth, std::string db_root,
td::actor::ActorId<ArchiveLru> archive_lru, DbStatistics statistics)
: archive_id_(archive_id)
, key_blocks_only_(key_blocks_only)
, temp_(temp)
, finalized_(finalized)
, p_id_(archive_id_, key_blocks_only_, temp_)
, shard_split_depth_(temp || key_blocks_only ? 0 : shard_split_depth)
, db_root_(std::move(db_root))
, archive_lru_(std::move(archive_lru))
, statistics_(statistics) {
db_path_ = PSTRING() << db_root_ << p_id_.path() << p_id_.name() << ".index";
}
td::Result<ArchiveSlice::PackageInfo *> ArchiveSlice::choose_package(BlockSeqno masterchain_seqno, bool force) {
td::Result<ArchiveSlice::PackageInfo *> ArchiveSlice::choose_package(BlockSeqno masterchain_seqno,
ShardIdFull shard_prefix, bool force) {
if (temp_ || key_blocks_only_ || !sliced_mode_) {
return &packages_[0];
}
if (masterchain_seqno < archive_id_) {
return td::Status::Error(ErrorCode::notready, "too small masterchain seqno");
}
auto v = (masterchain_seqno - archive_id_) / slice_size_;
if (v >= packages_.size()) {
masterchain_seqno -= (masterchain_seqno - archive_id_) % slice_size_;
CHECK((masterchain_seqno - archive_id_) % slice_size_ == 0);
if (shard_split_depth_ == 0) {
shard_prefix = ShardIdFull{masterchainId};
} else if (!shard_prefix.is_masterchain()) {
shard_prefix.shard |= 1; // In case length is < split depth
shard_prefix = ton::shard_prefix(shard_prefix, shard_split_depth_);
}
auto it = id_to_package_.find({masterchain_seqno, shard_prefix});
if (it == id_to_package_.end()) {
if (!force) {
return td::Status::Error(ErrorCode::notready, "too big masterchain seqno");
return td::Status::Error(ErrorCode::notready, "no such package");
}
CHECK(v == packages_.size());
begin_transaction();
size_t v = packages_.size();
kv_->set("slices", td::to_string(v + 1)).ensure();
kv_->set(PSTRING() << "status." << v, "0").ensure();
kv_->set(PSTRING() << "version." << v, td::to_string(default_package_version())).ensure();
if (shard_split_depth_ > 0) {
kv_->set(PSTRING() << "info." << v, package_info_to_str(masterchain_seqno, shard_prefix)).ensure();
}
commit_transaction();
CHECK((masterchain_seqno - archive_id_) % slice_size_ == 0);
add_package(masterchain_seqno, 0, default_package_version());
add_package(masterchain_seqno, shard_prefix, 0, default_package_version());
return &packages_[v];
} else {
return &packages_[v];
return &packages_[it->second];
}
}
void ArchiveSlice::add_package(td::uint32 seqno, td::uint64 size, td::uint32 version) {
void ArchiveSlice::add_package(td::uint32 seqno, ShardIdFull shard_prefix, td::uint64 size, td::uint32 version) {
PackageId p_id{seqno, key_blocks_only_, temp_};
std::string path = PSTRING() << db_root_ << p_id.path() << p_id.name() << ".pack";
std::string path = PSTRING() << db_root_ << p_id.path() << get_package_file_name(p_id, shard_prefix);
auto R = Package::open(path, false, true);
if (R.is_error()) {
LOG(FATAL) << "failed to open/create archive '" << path << "': " << R.move_as_error();
@ -748,8 +818,9 @@ void ArchiveSlice::add_package(td::uint32 seqno, td::uint64 size, td::uint32 ver
statistics_.pack_statistics->record_open();
}
auto idx = td::narrow_cast<td::uint32>(packages_.size());
id_to_package_[{seqno, shard_prefix}] = idx;
if (finalized_) {
packages_.emplace_back(nullptr, td::actor::ActorOwn<PackageWriter>(), seqno, path, idx, version);
packages_.emplace_back(nullptr, td::actor::ActorOwn<PackageWriter>(), seqno, shard_prefix, path, idx, version);
return;
}
auto pack = std::make_shared<Package>(R.move_as_ok());
@ -757,7 +828,7 @@ void ArchiveSlice::add_package(td::uint32 seqno, td::uint64 size, td::uint32 ver
pack->truncate(size).ensure();
}
auto writer = td::actor::create_actor<PackageWriter>("writer", pack, async_mode_, statistics_.pack_statistics);
packages_.emplace_back(std::move(pack), std::move(writer), seqno, path, idx, version);
packages_.emplace_back(std::move(pack), std::move(writer), seqno, shard_prefix, path, idx, version);
}
namespace {
@ -790,6 +861,7 @@ void ArchiveSlice::destroy(td::Promise<td::Unit> promise) {
statistics_.pack_statistics->record_close(packages_.size());
}
packages_.clear();
id_to_package_.clear();
kv_ = nullptr;
delay_action([name = db_path_, attempt = 0,
@ -861,7 +933,7 @@ void ArchiveSlice::move_handle(ConstBlockHandle handle, Package *old_pack, Packa
move_file(fileref::Block{handle->id()}, old_pack, pack);
}
bool ArchiveSlice::truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block_id, td::uint32 cutoff_idx,
bool ArchiveSlice::truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block_id, td::uint32 cutoff_seqno,
Package *pack) {
std::string value;
auto R = kv_->get(get_db_key_block_info(block_id), value);
@ -876,18 +948,18 @@ bool ArchiveSlice::truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block
return false;
}
auto S = choose_package(seqno, false);
auto S = choose_package(seqno, block_id.shard_full(), false);
S.ensure();
auto p = S.move_as_ok();
CHECK(p->idx <= cutoff_idx);
if (p->idx == cutoff_idx) {
CHECK(p->seqno <= cutoff_seqno);
if (p->seqno == cutoff_seqno) {
move_handle(std::move(handle), p->package.get(), pack);
}
return true;
}
void ArchiveSlice::truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shard, td::uint32 cutoff_idx,
void ArchiveSlice::truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shard, td::uint32 cutoff_seqno,
Package *pack) {
auto key = get_db_key_lt_desc(shard);
std::string value;
@ -913,7 +985,7 @@ void ArchiveSlice::truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shar
E.ensure();
auto e = E.move_as_ok();
if (truncate_block(masterchain_seqno, create_block_id(e->id_), cutoff_idx, pack)) {
if (truncate_block(masterchain_seqno, create_block_id(e->id_), cutoff_seqno, pack)) {
CHECK(new_last_idx == i);
new_last_idx = i + 1;
}
@ -925,7 +997,7 @@ void ArchiveSlice::truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shar
}
}
void ArchiveSlice::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle handle, td::Promise<td::Unit> promise) {
void ArchiveSlice::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle, td::Promise<td::Unit> promise) {
if (temp_ || archive_id_ > masterchain_seqno) {
destroy(std::move(promise));
return;
@ -938,15 +1010,8 @@ void ArchiveSlice::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle handl
return;
}
auto cutoff = choose_package(masterchain_seqno, false);
cutoff.ensure();
auto pack = cutoff.move_as_ok();
CHECK(pack);
auto pack_r = Package::open(pack->path + ".new", false, true);
pack_r.ensure();
auto new_package = std::make_shared<Package>(pack_r.move_as_ok());
new_package->truncate(0).ensure();
std::map<ShardIdFull, PackageInfo*> old_packages;
std::map<ShardIdFull, std::shared_ptr<Package>> new_packages;
std::string value;
auto status_key = create_serialize_tl_object<ton_api::db_lt_status_key>();
@ -967,38 +1032,71 @@ void ArchiveSlice::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle handl
auto G = fetch_tl_object<ton_api::db_lt_shard_value>(value, true);
G.ensure();
auto g = G.move_as_ok();
ShardIdFull shard{g->workchain_, static_cast<td::uint64>(g->shard_)};
truncate_shard(masterchain_seqno, ShardIdFull{g->workchain_, static_cast<td::uint64>(g->shard_)}, pack->idx,
new_package.get());
auto package_r = choose_package(masterchain_seqno, shard, false);
if (package_r.is_error()) {
continue;
}
auto package = package_r.move_as_ok();
CHECK(package);
if (!old_packages.count(package->shard_prefix)) {
old_packages[package->shard_prefix] = package;
auto new_package_r = Package::open(package->path + ".new", false, true);
new_package_r.ensure();
auto new_package = std::make_shared<Package>(new_package_r.move_as_ok());
new_package->truncate(0).ensure();
new_packages[package->shard_prefix] = std::move(new_package);
}
truncate_shard(masterchain_seqno, shard, package->seqno, new_packages[package->shard_prefix].get());
}
for (auto& [shard_prefix, package] : old_packages) {
auto new_package = new_packages[shard_prefix];
CHECK(new_package);
package->package = new_package;
package->writer.reset();
td::unlink(package->path).ensure();
td::rename(package->path + ".new", package->path).ensure();
package->writer = td::actor::create_actor<PackageWriter>("writer", new_package, async_mode_);
}
std::vector<PackageInfo> new_packages_info;
if (!sliced_mode_) {
kv_->set("status", td::to_string(new_package->size())).ensure();
kv_->set("status", td::to_string(packages_.at(0).package->size())).ensure();
} else {
kv_->set(PSTRING() << "status." << pack->idx, td::to_string(new_package->size())).ensure();
for (size_t i = pack->idx + 1; i < packages_.size(); i++) {
for (PackageInfo &package : packages_) {
if (package.seqno <= masterchain_seqno) {
new_packages_info.push_back(std::move(package));
} else {
td::unlink(package.path).ensure();
}
}
id_to_package_.clear();
for (td::uint32 i = 0; i < new_packages_info.size(); ++i) {
PackageInfo &package = new_packages_info[i];
package.idx = i;
kv_->set(PSTRING() << "status." << i, td::to_string(package.package->size())).ensure();
kv_->set(PSTRING() << "version." << i, td::to_string(package.version)).ensure();
if (shard_split_depth_ > 0) {
kv_->set(PSTRING() << "info." << i, package_info_to_str(package.seqno, package.shard_prefix)).ensure();
}
id_to_package_[{package.seqno, package.shard_prefix}] = i;
}
for (size_t i = new_packages_info.size(); i < packages_.size(); i++) {
kv_->erase(PSTRING() << "status." << i);
kv_->erase(PSTRING() << "version." << i);
kv_->erase(PSTRING() << "info." << i);
}
kv_->set("slices", td::to_string(pack->idx + 1));
kv_->set("slices", td::to_string(new_packages_info.size()));
if (statistics_.pack_statistics) {
statistics_.pack_statistics->record_close(packages_.size() - new_packages_info.size());
}
packages_ = std::move(new_packages_info);
}
pack->package = new_package;
pack->writer.reset();
td::unlink(pack->path).ensure();
td::rename(pack->path + ".new", pack->path).ensure();
pack->writer = td::actor::create_actor<PackageWriter>("writer", new_package, async_mode_);
for (auto idx = pack->idx + 1; idx < packages_.size(); idx++) {
td::unlink(packages_[idx].path).ensure();
}
if (statistics_.pack_statistics) {
statistics_.pack_statistics->record_close(packages_.size() - pack->idx - 1);
}
packages_.erase(packages_.begin() + pack->idx + 1, packages_.end());
kv_->commit_transaction().ensure();
promise.set_value(td::Unit());
}

View file

@ -96,10 +96,10 @@ class ArchiveLru;
class ArchiveSlice : public td::actor::Actor {
public:
ArchiveSlice(td::uint32 archive_id, bool key_blocks_only, bool temp, bool finalized, std::string db_root,
td::actor::ActorId<ArchiveLru> archive_lru, DbStatistics statistics = {});
ArchiveSlice(td::uint32 archive_id, bool key_blocks_only, bool temp, bool finalized, td::uint32 shard_split_depth,
std::string db_root, td::actor::ActorId<ArchiveLru> archive_lru, DbStatistics statistics = {});
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise);
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise);
void add_handle(BlockHandle handle, td::Promise<td::Unit> promise);
void update_handle(BlockHandle handle, td::Promise<td::Unit> promise);
@ -159,6 +159,7 @@ class ArchiveSlice : public td::actor::Actor {
bool sliced_mode_{false};
td::uint32 huge_transaction_size_ = 0;
td::uint32 slice_size_{100};
td::uint32 shard_split_depth_ = 0;
enum Status {
st_closed, st_open, st_want_close
@ -171,28 +172,31 @@ class ArchiveSlice : public td::actor::Actor {
std::unique_ptr<td::KeyValue> kv_;
struct PackageInfo {
PackageInfo(std::shared_ptr<Package> package, td::actor::ActorOwn<PackageWriter> writer, BlockSeqno id,
PackageInfo(std::shared_ptr<Package> package, td::actor::ActorOwn<PackageWriter> writer, BlockSeqno seqno, ShardIdFull shard_prefix,
std::string path, td::uint32 idx, td::uint32 version)
: package(std::move(package))
, writer(std ::move(writer))
, id(id)
, seqno(seqno)
, shard_prefix(shard_prefix)
, path(std::move(path))
, idx(idx)
, version(version) {
}
std::shared_ptr<Package> package;
td::actor::ActorOwn<PackageWriter> writer;
BlockSeqno id;
BlockSeqno seqno;
ShardIdFull shard_prefix;
std::string path;
td::uint32 idx;
td::uint32 version;
};
std::vector<PackageInfo> packages_;
std::map<std::pair<BlockSeqno, ShardIdFull>, td::uint32> id_to_package_;
td::Result<PackageInfo *> choose_package(BlockSeqno masterchain_seqno, bool force);
void add_package(BlockSeqno masterchain_seqno, td::uint64 size, td::uint32 version);
void truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shard, td::uint32 cutoff_idx, Package *pack);
bool truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block_id, td::uint32 cutoff_idx, Package *pack);
td::Result<PackageInfo *> choose_package(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, bool force);
void add_package(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::uint64 size, td::uint32 version);
void truncate_shard(BlockSeqno masterchain_seqno, ShardIdFull shard, td::uint32 cutoff_seqno, Package *pack);
bool truncate_block(BlockSeqno masterchain_seqno, BlockIdExt block_id, td::uint32 cutoff_seqno, Package *pack);
void delete_handle(ConstBlockHandle handle);
void delete_file(FileReference ref_id);

View file

@ -25,11 +25,27 @@ namespace ton {
namespace validator {
BlockArchiver::BlockArchiver(BlockHandle handle, td::actor::ActorId<ArchiveManager> archive_db,
td::Promise<td::Unit> promise)
: handle_(std::move(handle)), archive_(archive_db), promise_(std::move(promise)) {
td::actor::ActorId<Db> db, td::Promise<td::Unit> promise)
: handle_(std::move(handle)), archive_(archive_db), db_(std::move(db)), promise_(std::move(promise)) {
}
void BlockArchiver::start_up() {
if (handle_->id().is_masterchain()) {
td::actor::send_closure(db_, &Db::get_block_state, handle_,
[SelfId = actor_id(this), archive = archive_](td::Result<td::Ref<ShardState>> R) {
R.ensure();
td::Ref<MasterchainState> state{R.move_as_ok()};
td::uint32 monitor_min_split = state->monitor_min_split_depth(basechainId);
td::actor::send_closure(archive, &ArchiveManager::set_current_shard_split_depth,
monitor_min_split);
td::actor::send_closure(SelfId, &BlockArchiver::move_handle);
});
} else {
move_handle();
}
}
void BlockArchiver::move_handle() {
if (handle_->handle_moved_to_archive()) {
moved_handle();
} else {

View file

@ -33,11 +33,13 @@ class FileDb;
class BlockArchiver : public td::actor::Actor {
public:
BlockArchiver(BlockHandle handle, td::actor::ActorId<ArchiveManager> archive_db, td::Promise<td::Unit> promise);
BlockArchiver(BlockHandle handle, td::actor::ActorId<ArchiveManager> archive_db, td::actor::ActorId<Db> db,
td::Promise<td::Unit> promise);
void abort_query(td::Status error);
void start_up() override;
void move_handle();
void moved_handle();
void got_proof(td::BufferSlice data);
void written_proof();
@ -50,6 +52,7 @@ class BlockArchiver : public td::actor::Actor {
private:
BlockHandle handle_;
td::actor::ActorId<ArchiveManager> archive_;
td::actor::ActorId<Db> db_;
td::Promise<td::Unit> promise_;
};

View file

@ -347,7 +347,8 @@ void RootDb::try_get_static_file(FileHash file_hash, td::Promise<td::BufferSlice
}
void RootDb::apply_block(BlockHandle handle, td::Promise<td::Unit> promise) {
td::actor::create_actor<BlockArchiver>("archiver", std::move(handle), archive_db_.get(), std::move(promise))
td::actor::create_actor<BlockArchiver>("archiver", std::move(handle), archive_db_.get(), actor_id(this),
std::move(promise))
.release();
}
@ -421,7 +422,8 @@ void RootDb::start_up() {
}
void RootDb::archive(BlockHandle handle, td::Promise<td::Unit> promise) {
td::actor::create_actor<BlockArchiver>("archiveblock", std::move(handle), archive_db_.get(), std::move(promise))
td::actor::create_actor<BlockArchiver>("archiveblock", std::move(handle), archive_db_.get(), actor_id(this),
std::move(promise))
.release();
}
@ -501,8 +503,9 @@ void RootDb::check_key_block_proof_link_exists(BlockIdExt block_id, td::Promise<
std::move(P));
}
void RootDb::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) {
td::actor::send_closure(archive_db_, &ArchiveManager::get_archive_id, masterchain_seqno, std::move(promise));
void RootDb::get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise) {
td::actor::send_closure(archive_db_, &ArchiveManager::get_archive_id, masterchain_seqno, shard_prefix,
std::move(promise));
}
void RootDb::get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
@ -519,6 +522,14 @@ void RootDb::run_gc(UnixTime mc_ts, UnixTime gc_ts, UnixTime archive_ttl) {
td::actor::send_closure(archive_db_, &ArchiveManager::run_gc, mc_ts, gc_ts, archive_ttl);
}
void RootDb::add_persistent_state_description(td::Ref<PersistentStateDescription> desc, td::Promise<td::Unit> promise) {
td::actor::send_closure(state_db_, &StateDb::add_persistent_state_description, std::move(desc), std::move(promise));
}
void RootDb::get_persistent_state_descriptions(td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise) {
td::actor::send_closure(state_db_, &StateDb::get_persistent_state_descriptions, std::move(promise));
}
} // namespace validator
} // namespace ton

View file

@ -132,12 +132,15 @@ class RootDb : public Db {
void check_key_block_proof_exists(BlockIdExt block_id, td::Promise<bool> promise) override;
void check_key_block_proof_link_exists(BlockIdExt block_id, td::Promise<bool> promise) override;
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) override;
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise) override;
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
td::Promise<td::BufferSlice> promise) override;
void set_async_mode(bool mode, td::Promise<td::Unit> promise) override;
void run_gc(UnixTime mc_ts, UnixTime gc_ts, UnixTime archive_ttl) override;
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc, td::Promise<td::Unit> promise) override;
void get_persistent_state_descriptions(td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise) override;
private:
td::actor::ActorId<ValidatorManager> validator_manager_;

View file

@ -240,6 +240,101 @@ void StateDb::start_up() {
}
}
void StateDb::add_persistent_state_description(td::Ref<PersistentStateDescription> desc,
td::Promise<td::Unit> promise) {
std::string value;
auto list_key = create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionsList>();
auto R = kv_->get(list_key.as_slice(), value);
R.ensure();
tl_object_ptr<ton_api::db_state_persistentStateDescriptionsList> list;
if (R.ok() == td::KeyValue::GetStatus::Ok) {
auto F = fetch_tl_object<ton_api::db_state_persistentStateDescriptionsList>(value, true);
F.ensure();
list = F.move_as_ok();
} else {
list = create_tl_object<ton_api::db_state_persistentStateDescriptionsList>(
std::vector<tl_object_ptr<ton_api::db_state_persistentStateDescriptionHeader>>());
}
for (const auto& obj : list->list_) {
if ((BlockSeqno)obj->masterchain_id_->seqno_ == desc->masterchain_id.seqno()) {
promise.set_error(td::Status::Error("duplicate masterchain seqno"));
return;
}
}
auto now = (UnixTime)td::Clocks::system();
size_t new_size = 0;
kv_->begin_write_batch().ensure();
for (auto& obj : list->list_) {
auto end_time = (UnixTime)obj->end_time_;
if (end_time <= now) {
auto key =
create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionShards>(obj->masterchain_id_->seqno_);
kv_->erase(key.as_slice()).ensure();
} else {
list->list_[new_size++] = std::move(obj);
}
}
list->list_.resize(new_size);
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> shard_blocks;
for (const BlockIdExt& block_id : desc->shard_blocks) {
shard_blocks.push_back(create_tl_block_id(block_id));
}
auto key =
create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionShards>(desc->masterchain_id.seqno());
kv_->set(key.as_slice(),
create_serialize_tl_object<ton_api::db_state_persistentStateDescriptionShards>(std::move(shard_blocks))
.as_slice())
.ensure();
list->list_.push_back(create_tl_object<ton_api::db_state_persistentStateDescriptionHeader>(
create_tl_block_id(desc->masterchain_id), desc->start_time, desc->end_time));
kv_->set(list_key.as_slice(), serialize_tl_object(list, true).as_slice()).ensure();
kv_->commit_write_batch().ensure();
promise.set_result(td::Unit());
}
void StateDb::get_persistent_state_descriptions(td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise) {
std::string value;
auto R = kv_->get(create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionsList>().as_slice(), value);
R.ensure();
if (R.ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_value({});
return;
}
auto F = fetch_tl_object<ton_api::db_state_persistentStateDescriptionsList>(value, true);
F.ensure();
std::vector<td::Ref<PersistentStateDescription>> result;
auto now = (UnixTime)td::Clocks::system();
for (const auto& obj : F.ok()->list_) {
auto end_time = (UnixTime)obj->end_time_;
if (end_time <= now) {
continue;
}
PersistentStateDescription desc;
desc.start_time = (UnixTime)obj->start_time_;
desc.end_time = end_time;
desc.masterchain_id = create_block_id(obj->masterchain_id_);
auto key =
create_hash_tl_object<ton_api::db_state_key_persistentStateDescriptionShards>(desc.masterchain_id.seqno());
auto R2 = kv_->get(key.as_slice(), value);
R2.ensure();
if (R2.ok() == td::KeyValue::GetStatus::NotFound) {
continue;
}
auto F2 = fetch_tl_object<ton_api::db_state_persistentStateDescriptionShards>(value, true);
F2.ensure();
for (const auto& block_id : F2.ok()->shard_blocks_) {
desc.shard_blocks.push_back(create_block_id(block_id));
}
result.push_back(td::Ref<PersistentStateDescription>(true, std::move(desc)));
}
promise.set_result(std::move(result));
}
void StateDb::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle handle, td::Promise<td::Unit> promise) {
{
auto key = create_hash_tl_object<ton_api::db_state_key_asyncSerializer>();

View file

@ -50,6 +50,9 @@ class StateDb : public td::actor::Actor {
void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise);
void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise);
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc, td::Promise<td::Unit> promise);
void get_persistent_state_descriptions(td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise);
StateDb(td::actor::ActorId<RootDb> root_db, std::string path);
void start_up() override;

View file

@ -106,13 +106,24 @@ void WaitBlockData::start() {
});
td::actor::send_closure(manager_, &ValidatorManager::try_get_static_file, handle_->id().file_hash, std::move(P));
} else if (try_get_candidate_) {
try_get_candidate_ = false;
td::actor::send_closure(
manager_, &ValidatorManager::get_candidate_data_by_block_id_from_db, handle_->id(),
[SelfId = actor_id(this), id = handle_->id()](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &WaitBlockData::start);
} else {
td::actor::send_closure(SelfId, &WaitBlockData::loaded_data, ReceivedBlock{id, R.move_as_ok()});
}
});
} else {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &WaitBlockData::failed_to_get_block_data_from_net,
R.move_as_error_prefix("net error: "));
} else {
td::actor::send_closure(SelfId, &WaitBlockData::got_data_from_net, R.move_as_ok());
td::actor::send_closure(SelfId, &WaitBlockData::loaded_data, R.move_as_ok());
}
});
@ -137,16 +148,16 @@ void WaitBlockData::failed_to_get_block_data_from_net(td::Status reason) {
td::Timestamp::in(0.1));
}
void WaitBlockData::got_data_from_net(ReceivedBlock block) {
void WaitBlockData::loaded_data(ReceivedBlock block) {
auto X = create_block(std::move(block));
if (X.is_error()) {
failed_to_get_block_data_from_net(X.move_as_error_prefix("bad block from net: "));
return;
}
got_block_data_from_net(X.move_as_ok());
loaded_block_data(X.move_as_ok());
}
void WaitBlockData::got_block_data_from_net(td::Ref<BlockData> block) {
void WaitBlockData::loaded_block_data(td::Ref<BlockData> block) {
if (data_.not_null()) {
return;
}

View file

@ -30,15 +30,16 @@ class ValidatorManager;
class WaitBlockData : public td::actor::Actor {
public:
WaitBlockData(BlockHandle handle, td::uint32 priority, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<td::Ref<BlockData>> promise)
td::Timestamp timeout, bool try_get_candidate, td::Promise<td::Ref<BlockData>> promise)
: handle_(std::move(handle))
, priority_(priority)
, manager_(manager)
, timeout_(timeout)
, try_get_candidate_(try_get_candidate)
, promise_(std::move(promise))
, perf_timer_("waitdata", 1.0, [manager](double duration) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "waitdata", duration);
}) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "waitdata", duration);
}) {
}
void update_timeout(td::Timestamp timeout, td::uint32 priority) {
@ -57,8 +58,8 @@ class WaitBlockData : public td::actor::Actor {
void set_is_hardfork(bool value);
void start();
void got_block_data_from_db(td::Ref<BlockData> data);
void got_data_from_net(ReceivedBlock data);
void got_block_data_from_net(td::Ref<BlockData> block);
void loaded_data(ReceivedBlock data);
void loaded_block_data(td::Ref<BlockData> block);
void checked_proof_link();
void failed_to_get_block_data_from_net(td::Status reason);
@ -73,6 +74,7 @@ class WaitBlockData : public td::actor::Actor {
td::actor::ActorId<ValidatorManager> manager_;
td::Timestamp timeout_;
bool try_get_candidate_;
td::Promise<td::Ref<BlockData>> promise_;
td::Ref<BlockData> data_;

View file

@ -21,6 +21,7 @@
#include "ton/ton-io.hpp"
#include "common/checksum.h"
#include "common/delay.h"
#include "validator/downloaders/download-state.hpp"
namespace ton {
@ -106,6 +107,19 @@ void WaitBlockState::start() {
});
td::actor::send_closure(manager_, &ValidatorManager::send_get_zero_state_request, handle_->id(), priority_,
std::move(P));
} else if (check_persistent_state_desc()) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) {
LOG(WARNING) << "failed to get persistent state: " << R.move_as_error();
td::actor::send_closure(SelfId, &WaitBlockState::start);
} else {
td::actor::send_closure(SelfId, &WaitBlockState::written_state, R.move_as_ok());
}
});
BlockIdExt masterchain_id = persistent_state_desc_->masterchain_id;
td::actor::create_actor<DownloadShardState>("downloadstate", handle_->id(), masterchain_id, priority_, manager_,
timeout_, std::move(P))
.release();
} else if (!handle_->inited_prev() || (!handle_->inited_proof() && !handle_->inited_proof_link())) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle = handle_](td::Result<td::BufferSlice> R) {
if (R.is_error()) {

View file

@ -27,12 +27,14 @@ namespace validator {
class WaitBlockState : public td::actor::Actor {
public:
WaitBlockState(BlockHandle handle, td::uint32 priority, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<td::Ref<ShardState>> promise)
td::Timestamp timeout, td::Promise<td::Ref<ShardState>> promise,
td::Ref<PersistentStateDescription> persistent_state_desc = {})
: handle_(std::move(handle))
, priority_(priority)
, manager_(manager)
, timeout_(timeout)
, promise_(std::move(promise))
, persistent_state_desc_(std::move(persistent_state_desc))
, perf_timer_("waitstate", 1.0, [manager](double duration) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "waitstate", duration);
}) {
@ -90,6 +92,7 @@ class WaitBlockState : public td::actor::Actor {
td::actor::ActorId<ValidatorManager> manager_;
td::Timestamp timeout_;
td::Promise<td::Ref<ShardState>> promise_;
td::Ref<PersistentStateDescription> persistent_state_desc_;
td::Ref<ShardState> prev_state_;
td::Ref<BlockData> block_;
@ -99,7 +102,15 @@ class WaitBlockState : public td::actor::Actor {
bool waiting_proof_ = false;
td::Timestamp next_static_file_attempt_;
td::PerfWarningTimer perf_timer_;
td::PerfWarningTimer perf_timer_{"waitstate", 1.0};
bool check_persistent_state_desc() const {
if (persistent_state_desc_.is_null()) {
return false;
}
auto now = (UnixTime)td::Clocks::system();
return persistent_state_desc_->end_time > now + 3600 && persistent_state_desc_->start_time < now - 6 * 3600;
}
};
} // namespace validator

View file

@ -371,7 +371,8 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getCapabilities &query,
td::Promise<td::BufferSlice> promise) {
promise.set_value(create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version(), proto_capabilities()));
promise.set_value(
create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version_major(), proto_version_minor(), 0));
}
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveInfo &query,
@ -385,7 +386,7 @@ void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNo
}
});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_archive_id, query.masterchain_seqno_,
std::move(P));
ShardIdFull{masterchainId}, std::move(P));
}
void FullNodeMasterImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,

View file

@ -28,10 +28,10 @@ namespace fullnode {
class FullNodeMasterImpl : public FullNodeMaster {
public:
static constexpr td::uint32 proto_version() {
static constexpr td::uint32 proto_version_major() {
return 1;
}
static constexpr td::uint64 proto_capabilities() {
static constexpr td::uint32 proto_version_minor() {
return 0;
}
void start_up() override;

View file

@ -20,6 +20,7 @@
#include "checksum.h"
#include "overlays.h"
#include "td/utils/SharedSlice.h"
#include "td/utils/overloaded.h"
#include "full-node-shard.hpp"
#include "full-node-shard-queries.hpp"
#include "full-node-serializer.hpp"
@ -27,7 +28,6 @@
#include "td/utils/buffer.h"
#include "ton/ton-shard.h"
#include "ton/ton-tl.hpp"
#include "ton/ton-io.hpp"
#include "adnl/utils.hpp"
#include "net/download-block-new.hpp"
@ -41,6 +41,9 @@
#include "td/utils/Random.h"
#include "common/delay.h"
#include "td/utils/JsonBuilder.h"
#include "tl/tl_json.h"
#include "auto/tl/ton_api_json.h"
namespace ton {
@ -50,9 +53,10 @@ namespace fullnode {
Neighbour Neighbour::zero = Neighbour{adnl::AdnlNodeIdShort::zero()};
void Neighbour::update_proto_version(const ton_api::tonNode_capabilities &q) {
proto_version = q.version_;
capabilities = q.capabilities_;
void Neighbour::update_proto_version(ton_api::tonNode_capabilities &q) {
version_major = q.version_major_;
version_minor = q.version_minor_;
flags = q.flags_;
}
void Neighbour::query_success(double t) {
@ -74,8 +78,9 @@ void Neighbour::update_roundtrip(double t) {
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_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id,
td::BufferSlice data) override {
td::actor::send_closure(node_, &FullNodeShardImpl::receive_message, src, std::move(data));
}
void receive_query(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
@ -88,15 +93,22 @@ void FullNodeShardImpl::create_overlay() {
td::Promise<td::Unit> promise) override {
td::actor::send_closure(node_, &FullNodeShardImpl::check_broadcast, src, std::move(data), std::move(promise));
}
void get_stats_extra(td::Promise<std::string> promise) override {
td::actor::send_closure(node_, &FullNodeShardImpl::get_stats_extra, std::move(promise));
}
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_, PSTRING() << "{ \"type\": \"shard\", \"shard_id\": " << get_shard() << ", \"workchain_id\": " << get_workchain() << " }");
overlay::OverlayOptions opts;
opts.announce_self_ = active_;
td::actor::send_closure(overlays_, &overlay::Overlays::create_public_overlay_ex, adnl_id_, overlay_id_full_.clone(),
std::make_unique<Callback>(actor_id(this)), rules_,
PSTRING() << "{ \"type\": \"shard\", \"shard_id\": " << get_shard()
<< ", \"workchain_id\": " << get_workchain() << " }",
opts);
td::actor::send_closure(rldp_, &rldp::Rldp::add_id, adnl_id_);
td::actor::send_closure(rldp2_, &rldp2::Rldp::add_id, adnl_id_);
@ -106,6 +118,9 @@ void FullNodeShardImpl::create_overlay() {
}
void FullNodeShardImpl::check_broadcast(PublicKeyHash src, td::BufferSlice broadcast, td::Promise<td::Unit> promise) {
if (!active_) {
return promise.set_error(td::Status::Error("cannot check broadcast: shard is not active"));
}
auto B = fetch_tl_object<ton_api::tonNode_externalMessageBroadcast>(std::move(broadcast), true);
if (B.is_error()) {
return promise.set_error(B.move_as_error_prefix("failed to parse external message broadcast: "));
@ -134,6 +149,10 @@ void FullNodeShardImpl::check_broadcast(PublicKeyHash src, td::BufferSlice broad
promise.wrap([](td::Ref<ExtMessage>) { return td::Unit(); }));
}
void FullNodeShardImpl::remove_neighbour(adnl::AdnlNodeIdShort id) {
neighbours_.erase(id);
}
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;
@ -141,6 +160,18 @@ void FullNodeShardImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promis
create_overlay();
}
void FullNodeShardImpl::set_active(bool active) {
if (shard_.is_masterchain()) {
return;
}
if (active_ == active) {
return;
}
active_ = active;
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, adnl_id_, overlay_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"));
@ -148,7 +179,7 @@ void FullNodeShardImpl::try_get_next_block(td::Timestamp timeout, td::Promise<Re
}
auto &b = choose_neighbour();
if (!b.adnl_id.is_zero() && b.proto_version >= 1) {
if (!b.adnl_id.is_zero() && b.version_major >= 1) {
VLOG(FULL_NODE_DEBUG) << "using new download method with adnlid=" << b.adnl_id;
td::actor::create_actor<DownloadBlockNew>("downloadnext", adnl_id_, overlay_id_, handle_->id(), b.adnl_id,
download_next_priority(), timeout, validator_manager_, rldp_, overlays_,
@ -187,7 +218,6 @@ void FullNodeShardImpl::got_next_block(td::Result<BlockHandle> R) {
}
void FullNodeShardImpl::get_next_block() {
//return;
attempt_++;
auto P = td::PromiseCreator::lambda([validator_manager = validator_manager_, attempt = attempt_,
block_id = handle_->id(), SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
@ -591,7 +621,8 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getCapabilities &query,
td::Promise<td::BufferSlice> promise) {
VLOG(FULL_NODE_DEBUG) << "Got query getCapabilities from " << src;
promise.set_value(create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version(), proto_capabilities()));
promise.set_value(
create_serialize_tl_object<ton_api::tonNode_capabilities>(proto_version_major(), proto_version_minor(), 0));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveInfo &query,
@ -606,7 +637,24 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
});
VLOG(FULL_NODE_DEBUG) << "Got query getArchiveInfo " << query.masterchain_seqno_ << " from " << src;
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_archive_id, query.masterchain_seqno_,
std::move(P));
ShardIdFull{masterchainId}, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getShardArchiveInfo &query,
td::Promise<td::BufferSlice> promise) {
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), promise = std::move(promise)](td::Result<td::uint64> R) mutable {
if (R.is_error()) {
promise.set_value(create_serialize_tl_object<ton_api::tonNode_archiveNotFound>());
} else {
promise.set_value(create_serialize_tl_object<ton_api::tonNode_archiveInfo>(R.move_as_ok()));
}
});
ShardIdFull shard_prefix = create_shard_id(query.shard_prefix_);
VLOG(FULL_NODE_DEBUG) << "Got query getShardArchiveInfo " << query.masterchain_seqno_ << " " << shard_prefix.to_str()
<< " from " << src;
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::get_archive_id, query.masterchain_seqno_,
shard_prefix, std::move(P));
}
void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,
@ -623,6 +671,12 @@ void FullNodeShardImpl::process_query(adnl::AdnlNodeIdShort src, ton_api::tonNod
void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query,
td::Promise<td::BufferSlice> promise) {
if (!active_) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_message, src, adnl_id_, overlay_id_,
create_serialize_tl_object<ton_api::tonNode_forgetPeer>());
promise.set_error(td::Status::Error("shard is inactive"));
return;
}
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"));
@ -631,6 +685,16 @@ void FullNodeShardImpl::receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice
ton_api::downcast_call(*B.move_as_ok().get(), [&](auto &obj) { this->process_query(src, obj, std::move(promise)); });
}
void FullNodeShardImpl::receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data) {
auto B = fetch_tl_object<ton_api::tonNode_forgetPeer>(std::move(data), true);
if (B.is_error()) {
return;
}
VLOG(FULL_NODE_DEBUG) << "Got tonNode.forgetPeer from " << src;
neighbours_.erase(src);
td::actor::send_closure(overlays_, &overlay::Overlays::forget_peer, adnl_id_, overlay_id_, src);
}
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_));
@ -691,11 +755,19 @@ void FullNodeShardImpl::process_block_broadcast(PublicKeyHash src, ton_api::tonN
LOG(DEBUG) << "dropped broadcast: " << B.move_as_error();
return;
}
//if (!shard_is_ancestor(shard_, block_id.shard_full())) {
// LOG(FULL_NODE_WARNING) << "dropping block broadcast: shard mismatch. overlay=" << shard_.to_str()
// << " block=" << block_id.to_str();
// return;
//}
VLOG(FULL_NODE_DEBUG) << "Received block broadcast from " << src << ": " << B.ok().block_id.to_str();
td::actor::send_closure(full_node_, &FullNode::process_block_broadcast, B.move_as_ok());
}
void FullNodeShardImpl::receive_broadcast(PublicKeyHash src, td::BufferSlice broadcast) {
if (!active_) {
return;
}
auto B = fetch_tl_object<ton_api::tonNode_Broadcast>(std::move(broadcast), true);
if (B.is_error()) {
return;
@ -804,7 +876,7 @@ void FullNodeShardImpl::send_broadcast(BlockBroadcast broadcast) {
void FullNodeShardImpl::download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<ReceivedBlock> promise) {
auto &b = choose_neighbour();
if (!b.adnl_id.is_zero() && b.proto_version >= 1) {
if (!b.adnl_id.is_zero() && b.version_major >= 1) {
VLOG(FULL_NODE_DEBUG) << "new block download";
td::actor::create_actor<DownloadBlockNew>("downloadreq", id, adnl_id_, overlay_id_, b.adnl_id, priority, timeout,
validator_manager_, rldp_, overlays_, adnl_, client_,
@ -863,12 +935,12 @@ void FullNodeShardImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp t
.release();
}
void FullNodeShardImpl::download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
td::Promise<std::string> promise) {
void FullNodeShardImpl::download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) {
auto &b = choose_neighbour();
td::actor::create_actor<DownloadArchiveSlice>("archive", masterchain_seqno, std::move(tmp_dir), adnl_id_, overlay_id_,
b.adnl_id, timeout, validator_manager_, rldp2_, overlays_, adnl_,
client_, create_neighbour_promise(b, std::move(promise)))
td::actor::create_actor<DownloadArchiveSlice>(
"archive", masterchain_seqno, shard_prefix, std::move(tmp_dir), adnl_id_, overlay_id_, b.adnl_id, timeout,
validator_manager_, rldp2_, overlays_, adnl_, client_, create_neighbour_promise(b, std::move(promise)))
.release();
}
@ -936,6 +1008,10 @@ void FullNodeShardImpl::start_up() {
}
}
void FullNodeShardImpl::tear_down() {
td::actor::send_closure(overlays_, &ton::overlay::Overlays::delete_overlay, adnl_id_, overlay_id_);
}
void FullNodeShardImpl::sign_new_certificate(PublicKeyHash sign_by) {
if (sign_by.is_zero()) {
return;
@ -1083,15 +1159,19 @@ const Neighbour &FullNodeShardImpl::choose_neighbour() const {
return Neighbour::zero;
}
double min_unreliability = 1e9;
for (auto &x : neighbours_) {
min_unreliability = std::min(min_unreliability, x.second.unreliability);
}
const Neighbour *best = nullptr;
td::uint32 sum = 0;
for (auto &x : neighbours_) {
td::uint32 unr = static_cast<td::uint32>(x.second.unreliability);
auto unr = static_cast<td::uint32>(x.second.unreliability - min_unreliability);
if (x.second.proto_version < proto_version()) {
if (x.second.version_major < proto_version_major()) {
unr += 4;
} else if (x.second.proto_version == proto_version() && x.second.capabilities < proto_capabilities()) {
} else if (x.second.version_major == proto_version_major() && x.second.version_minor < proto_version_minor()) {
unr += 2;
}
@ -1105,7 +1185,10 @@ const Neighbour &FullNodeShardImpl::choose_neighbour() const {
}
}
}
return best ? *best : Neighbour::zero;
if (best) {
return *best;
}
return Neighbour::zero;
}
void FullNodeShardImpl::update_neighbour_stats(adnl::AdnlNodeIdShort adnl_id, double t, bool success) {
@ -1128,7 +1211,7 @@ void FullNodeShardImpl::got_neighbour_capabilities(adnl::AdnlNodeIdShort adnl_id
if (F.is_error()) {
it->second.query_failed();
} else {
it->second.update_proto_version(*F.move_as_ok().get());
it->second.update_proto_version(*F.ok());
it->second.query_success(t);
}
}
@ -1157,7 +1240,7 @@ void FullNodeShardImpl::ping_neighbours() {
td::Time::now() - start_time, R.move_as_ok());
}
});
auto q = create_serialize_tl_object<ton_api::tonNode_getCapabilities>();
td::BufferSlice q = create_serialize_tl_object<ton_api::tonNode_getCapabilities>();
td::actor::send_closure(overlays_, &overlay::Overlays::send_query, it->first, adnl_id_, overlay_id_,
"get_prepare_block", std::move(P), td::Timestamp::in(1.0), std::move(q));
@ -1167,6 +1250,24 @@ void FullNodeShardImpl::ping_neighbours() {
}
}
void FullNodeShardImpl::get_stats_extra(td::Promise<std::string> promise) {
auto res = create_tl_object<ton_api::engine_validator_shardOverlayStats>();
res->shard_ = shard_.to_str();
res->active_ = active_;
for (const auto &p : neighbours_) {
const auto &n = p.second;
auto f = create_tl_object<ton_api::engine_validator_shardOverlayStats_neighbour>();
f->id_ = n.adnl_id.bits256_value().to_hex();
f->verison_major_ = n.version_major;
f->version_minor_ = n.version_minor;
f->flags_ = n.flags;
f->roundtrip_ = n.roundtrip;
f->unreliability_ = n.unreliability;
res->neighbours_.push_back(std::move(f));
}
promise.set_result(td::json_encode<std::string>(td::ToJson(*res), true));
}
FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, 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,
@ -1174,7 +1275,7 @@ FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id,
td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client,
td::actor::ActorId<FullNode> full_node)
td::actor::ActorId<FullNode> full_node, bool active)
: shard_(shard)
, local_id_(local_id)
, adnl_id_(adnl_id)
@ -1187,6 +1288,7 @@ FullNodeShardImpl::FullNodeShardImpl(ShardIdFull shard, PublicKeyHash local_id,
, validator_manager_(validator_manager)
, client_(client)
, full_node_(full_node)
, active_(active)
, config_(config) {
}
@ -1195,10 +1297,10 @@ td::actor::ActorOwn<FullNodeShard> FullNodeShard::create(
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<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node) {
return td::actor::create_actor<FullNodeShardImpl>("tonnode", shard, local_id, adnl_id, zero_state_file_hash, config,
keyring, adnl, rldp, rldp2, overlays, validator_manager, client,
full_node);
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node, bool active) {
return td::actor::create_actor<FullNodeShardImpl>(PSTRING() << "tonnode" << shard.to_str(), shard, local_id, adnl_id,
zero_state_file_hash, config, keyring, adnl, rldp, rldp2, overlays,
validator_manager, client, full_node, active);
}
} // namespace fullnode

View file

@ -36,6 +36,7 @@ class FullNodeShard : public td::actor::Actor {
virtual ShardIdFull get_shard_full() const = 0;
virtual void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) = 0;
virtual void set_active(bool active) = 0;
virtual void set_config(FullNodeConfig config) = 0;
virtual void send_ihr_message(td::BufferSlice data) = 0;
@ -45,9 +46,10 @@ class FullNodeShard : public td::actor::Actor {
td::BufferSlice data) = 0;
virtual void send_broadcast(BlockBroadcast broadcast) = 0;
virtual void sign_overlay_certificate(PublicKeyHash signed_key, td::uint32 expiry_at, td::uint32 max_size, td::Promise<td::BufferSlice> promise) = 0;
virtual void import_overlay_certificate(PublicKeyHash signed_key, std::shared_ptr<ton::overlay::Certificate> cert, td::Promise<td::Unit> promise) = 0;
virtual void sign_overlay_certificate(PublicKeyHash signed_key, td::uint32 expiry_at, td::uint32 max_size,
td::Promise<td::BufferSlice> promise) = 0;
virtual void import_overlay_certificate(PublicKeyHash signed_key, std::shared_ptr<ton::overlay::Certificate> cert,
td::Promise<td::Unit> promise) = 0;
virtual void download_block(BlockIdExt id, td::uint32 priority, td::Timestamp timeout,
td::Promise<ReceivedBlock> promise) = 0;
@ -62,8 +64,8 @@ class FullNodeShard : public td::actor::Actor {
td::Promise<td::BufferSlice> promise) = 0;
virtual void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
td::Promise<std::vector<BlockIdExt>> promise) = 0;
virtual void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
td::Promise<std::string> promise) = 0;
virtual void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
virtual void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
@ -74,7 +76,7 @@ class FullNodeShard : public td::actor::Actor {
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<overlay::Overlays> overlays, td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node);
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node, bool active);
};
} // namespace fullnode

View file

@ -32,16 +32,17 @@ namespace fullnode {
struct Neighbour {
adnl::AdnlNodeIdShort adnl_id;
td::uint32 proto_version = 0;
td::uint64 capabilities = 0;
td::uint32 version_major = 0;
td::uint32 version_minor = 0;
td::uint32 flags = 0;
double roundtrip = 0;
double roundtrip_relax_at = 0;
double roundtrip_weight = 0;
double unreliability = 0;
Neighbour(adnl::AdnlNodeIdShort adnl_id) : adnl_id(std::move(adnl_id)) {
explicit Neighbour(adnl::AdnlNodeIdShort adnl_id) : adnl_id(std::move(adnl_id)) {
}
void update_proto_version(const ton_api::tonNode_capabilities &q);
void update_proto_version(ton_api::tonNode_capabilities &q);
void query_success(double t);
void query_failed();
void update_roundtrip(double t);
@ -64,12 +65,12 @@ class FullNodeShardImpl : public FullNodeShard {
static constexpr td::uint32 download_next_priority() {
return 1;
}
static constexpr td::uint32 proto_version() {
return 2;
}
static constexpr td::uint64 proto_capabilities() {
static constexpr td::uint32 proto_version_major() {
return 3;
}
static constexpr td::uint32 proto_version_minor() {
return 0;
}
static constexpr td::uint32 max_neighbours() {
return 16;
}
@ -82,14 +83,12 @@ class FullNodeShardImpl : public FullNodeShard {
void create_overlay();
void update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) override;
void set_active(bool active) override;
void set_config(FullNodeConfig config) override {
config_ = config;
}
//td::Result<Block> fetch_block(td::BufferSlice data);
void prevalidate_block(BlockIdExt block_id, td::BufferSlice data, td::BufferSlice proof,
td::Promise<ReceivedBlock> promise);
void try_get_next_block(td::Timestamp timestamp, td::Promise<ReceivedBlock> promise);
void got_next_block(td::Result<BlockHandle> block);
void get_next_block();
@ -136,11 +135,14 @@ class FullNodeShardImpl : public FullNodeShard {
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveInfo &query,
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getShardArchiveInfo &query,
td::Promise<td::BufferSlice> promise);
void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_getArchiveSlice &query,
td::Promise<td::BufferSlice> promise);
// void process_query(adnl::AdnlNodeIdShort src, ton_api::tonNode_prepareNextKeyBlockProof &query,
// td::Promise<td::BufferSlice> promise);
void receive_query(adnl::AdnlNodeIdShort src, td::BufferSlice query, td::Promise<td::BufferSlice> promise);
void receive_message(adnl::AdnlNodeIdShort src, td::BufferSlice data);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcast &query);
void process_broadcast(PublicKeyHash src, ton_api::tonNode_blockBroadcastCompressed &query);
@ -156,6 +158,8 @@ class FullNodeShardImpl : public FullNodeShard {
void receive_broadcast(PublicKeyHash src, td::BufferSlice query);
void check_broadcast(PublicKeyHash src, td::BufferSlice query, td::Promise<td::Unit> promise);
void get_stats_extra(td::Promise<std::string> promise);
void remove_neighbour(adnl::AdnlNodeIdShort id);
void send_ihr_message(td::BufferSlice data) override;
void send_external_message(td::BufferSlice data) override;
@ -177,12 +181,13 @@ class FullNodeShardImpl : public FullNodeShard {
td::Promise<td::BufferSlice> promise) override;
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
td::Promise<std::vector<BlockIdExt>> promise) override;
void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
td::Promise<std::string> promise) override;
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) override;
void set_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
void start_up() override;
void tear_down() override;
void alarm() override;
void update_validators(std::vector<PublicKeyHash> public_key_hashes, PublicKeyHash local_hash) override;
@ -218,7 +223,8 @@ class FullNodeShardImpl : public FullNodeShard {
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node);
td::actor::ActorId<adnl::AdnlExtClient> client, td::actor::ActorId<FullNode> full_node,
bool active);
private:
bool use_new_download() const {
@ -258,6 +264,8 @@ class FullNodeShardImpl : public FullNodeShard {
td::Timestamp ping_neighbours_at_;
adnl::AdnlNodeIdShort last_pinged_neighbour_ = adnl::AdnlNodeIdShort::zero();
bool active_;
FullNodeConfig config_;
std::set<td::Bits256> my_ext_msg_broadcasts_;

View file

@ -17,10 +17,12 @@
Copyright 2017-2020 Telegram Systems LLP
*/
#include "full-node.hpp"
#include "ton/ton-shard.h"
#include "ton/ton-io.hpp"
#include "td/actor/MultiPromise.h"
#include "full-node.h"
#include "common/delay.h"
#include "td/utils/Random.h"
#include "ton/ton-tl.hpp"
namespace ton {
@ -28,6 +30,8 @@ namespace validator {
namespace fullnode {
static const double INACTIVE_SHARD_TTL = (double)overlay::Overlays::overlay_peer_ttl() + 60.0;
void FullNodeImpl::add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) {
if (local_keys_.count(key)) {
promise.set_value(td::Unit());
@ -52,7 +56,9 @@ void FullNodeImpl::add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> pr
}
for (auto &shard : shards_) {
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
if (!shard.second.actor.empty()) {
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
}
}
promise.set_value(td::Unit());
}
@ -82,30 +88,34 @@ void FullNodeImpl::del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> pr
}
for (auto &shard : shards_) {
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
if (!shard.second.actor.empty()) {
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
}
}
promise.set_value(td::Unit());
}
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) {
auto it = shards_.find(shard_id);
if(it == shards_.end()) {
promise.set_error(td::Status::Error(ErrorCode::error, "shard not found"));
return;
}
td::actor::send_closure(it->second, &FullNodeShard::sign_overlay_certificate, signed_key, expiry_at, max_size, std::move(promise));
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) {
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) {
auto it = shards_.find(shard_id);
if(it == shards_.end()) {
promise.set_error(td::Status::Error(ErrorCode::error, "shard not found"));
}
td::actor::send_closure(it->second, &FullNodeShard::import_overlay_certificate, signed_key, cert, std::move(promise));
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));
}
void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td::Unit> promise) {
@ -116,7 +126,9 @@ void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td:
ig.add_promise(std::move(promise));
for (auto &s : shards_) {
td::actor::send_closure(s.second, &FullNodeShard::update_adnl_id, adnl_id, ig.get_promise());
if (!s.second.actor.empty()) {
td::actor::send_closure(s.second.actor, &FullNodeShard::update_adnl_id, adnl_id, ig.get_promise());
}
}
local_id_ = adnl_id_.pubkey_hash();
@ -127,8 +139,10 @@ void FullNodeImpl::update_adnl_id(adnl::AdnlNodeIdShort adnl_id, td::Promise<td:
void FullNodeImpl::set_config(FullNodeConfig config) {
config_ = config;
for (auto& shard : shards_) {
td::actor::send_closure(shard.second, &FullNodeShard::set_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);
@ -173,32 +187,84 @@ void FullNodeImpl::initial_read_complete(BlockHandle top_handle) {
td::actor::send_closure(SelfId, &FullNodeImpl::sync_completed);
});
auto it = shards_.find(ShardIdFull{masterchainId});
CHECK(it != shards_.end());
td::actor::send_closure(it->second, &FullNodeShard::set_handle, top_handle, std::move(P));
CHECK(it != shards_.end() && !it->second.actor.empty());
td::actor::send_closure(it->second.actor, &FullNodeShard::set_handle, top_handle, std::move(P));
}
void FullNodeImpl::add_shard(ShardIdFull shard) {
while (true) {
if (shards_.count(shard) == 0) {
shards_.emplace(shard,
FullNodeShard::create(shard, local_id_, adnl_id_, zero_state_file_hash_, config_, keyring_, adnl_,
rldp_, rldp2_, overlays_, validator_manager_, client_, actor_id(this)));
if (all_validators_.size() > 0) {
td::actor::send_closure(shards_[shard], &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
void FullNodeImpl::on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor) {
CHECK(shards_to_monitor.count(ShardIdFull(masterchainId)));
bool join_all_overlays = !sign_cert_by_.is_zero();
std::set<ShardIdFull> all_shards;
std::set<ShardIdFull> new_active;
all_shards.insert(ShardIdFull(masterchainId));
std::set<WorkchainId> workchains;
wc_monitor_min_split_ = state->monitor_min_split_depth(basechainId);
auto cut_shard = [&](ShardIdFull shard) -> ShardIdFull {
return wc_monitor_min_split_ < shard.pfx_len() ? shard_prefix(shard, wc_monitor_min_split_) : shard;
};
for (auto &info : state->get_shards()) {
workchains.insert(info->shard().workchain);
ShardIdFull shard = cut_shard(info->shard());
while (true) {
all_shards.insert(shard);
if (shard.pfx_len() == 0) {
break;
}
shard = shard_parent(shard);
}
}
for (const auto &[wc, winfo] : state->get_workchain_list()) {
if (!workchains.contains(wc) && winfo->active && winfo->enabled_since <= state->get_unix_time()) {
all_shards.insert(ShardIdFull(wc));
}
}
for (ShardIdFull shard : shards_to_monitor) {
shard = cut_shard(shard);
while (true) {
new_active.insert(shard);
if (shard.pfx_len() == 0) {
break;
}
shard = shard_parent(shard);
}
}
for (auto it = shards_.begin(); it != shards_.end(); ) {
if (all_shards.contains(it->first)) {
++it;
} else {
break;
it = shards_.erase(it);
}
if (shard.shard == shardIdAll) {
break;
}
for (ShardIdFull shard : all_shards) {
bool active = new_active.contains(shard);
bool overlay_exists = !shards_[shard].actor.empty();
if (active || join_all_overlays || overlay_exists) {
update_shard_actor(shard, active);
}
}
for (auto &[_, shard_info] : shards_) {
if (!shard_info.active && shard_info.delete_at && shard_info.delete_at.is_in_past() && !join_all_overlays) {
shard_info.actor = {};
shard_info.delete_at = td::Timestamp::never();
}
shard = shard_parent(shard);
}
}
void FullNodeImpl::del_shard(ShardIdFull shard) {
LOG(FATAL) << "deleting shards not implemented: shard=" << shard;
shards_.erase(shard);
void FullNodeImpl::update_shard_actor(ShardIdFull shard, bool active) {
ShardInfo &info = shards_[shard];
if (info.actor.empty()) {
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), active);
if (!all_validators_.empty()) {
td::actor::send_closure(info.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
}
} else if (info.active != active) {
td::actor::send_closure(info.actor, &FullNodeShard::set_active, active);
}
info.active = active;
info.delete_at = active ? td::Timestamp::never() : td::Timestamp::in(INACTIVE_SHARD_TTL);
}
void FullNodeImpl::sync_completed() {
@ -206,7 +272,7 @@ void FullNodeImpl::sync_completed() {
}
void FullNodeImpl::send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) {
auto shard = get_shard(ShardIdFull{masterchainId});
auto shard = get_shard(dst);
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping OUT ihr message to unknown shard";
return;
@ -220,11 +286,12 @@ void FullNodeImpl::send_ext_message(AccountIdPrefixFull dst, td::BufferSlice dat
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());
for (auto &[_, private_overlay] : custom_overlays_) {
if (private_overlay.params_.send_shard(dst.as_leaf_shard())) {
for (auto &[local_id, actor] : private_overlay.actors_) {
if (private_overlay.params_.msg_senders_.contains(local_id)) {
td::actor::send_closure(actor, &FullNodeCustomOverlay::send_external_message, data.clone());
}
}
}
}
@ -232,7 +299,7 @@ void FullNodeImpl::send_ext_message(AccountIdPrefixFull dst, td::BufferSlice dat
}
void FullNodeImpl::send_shard_block_info(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
auto shard = get_shard(ShardIdFull{masterchainId, shardIdAll});
auto shard = get_shard(ShardIdFull{masterchainId});
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping OUT shard block info message to unknown shard";
return;
@ -266,14 +333,16 @@ void FullNodeImpl::send_broadcast(BlockBroadcast broadcast, int mode) {
if (mode & broadcast_mode_custom) {
send_block_broadcast_to_custom_overlays(broadcast);
}
auto shard = get_shard(ShardIdFull{masterchainId});
auto shard = get_shard(broadcast.block_id.shard_full());
if (shard.empty()) {
VLOG(FULL_NODE_WARNING) << "dropping OUT broadcast to unknown shard";
return;
}
if (!private_block_overlays_.empty() && (mode & broadcast_mode_private_block)) {
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_broadcast,
broadcast.clone());
if (mode & broadcast_mode_private_block) {
if (!private_block_overlays_.empty()) {
td::actor::send_closure(private_block_overlays_.begin()->second, &FullNodePrivateBlockOverlay::send_broadcast,
broadcast.clone());
}
}
if (mode & broadcast_mode_public) {
td::actor::send_closure(shard, &FullNodeShard::send_broadcast, std::move(broadcast));
@ -348,27 +417,43 @@ void FullNodeImpl::get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeou
td::actor::send_closure(shard, &FullNodeShard::get_next_key_blocks, block_id, timeout, std::move(promise));
}
void FullNodeImpl::download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
td::Promise<std::string> promise) {
auto shard = get_shard(ShardIdFull{masterchainId});
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;
}
CHECK(!shard.empty());
td::actor::send_closure(shard, &FullNodeShard::download_archive, masterchain_seqno, std::move(tmp_dir), timeout,
std::move(promise));
td::actor::send_closure(shard, &FullNodeShard::download_archive, masterchain_seqno, shard_prefix, std::move(tmp_dir),
timeout, std::move(promise));
}
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(ShardIdFull shard) {
add_shard(ShardIdFull{shard.workchain, shardIdAll});
while (shards_.count(shard) == 0) {
if (shard.shard == shardIdAll) {
return td::actor::ActorId<FullNodeShard>{};
}
shard = shard_parent(shard);
if (shard.is_masterchain()) {
return shards_[ShardIdFull{masterchainId}].actor.get();
}
return shards_[shard].get();
if (shard.workchain != basechainId) {
return {};
}
int pfx_len = shard.pfx_len();
if (pfx_len > wc_monitor_min_split_) {
shard = shard_prefix(shard, wc_monitor_min_split_);
}
auto it = shards_.find(shard);
if (it != shards_.end()) {
update_shard_actor(shard, it->second.active);
return it->second.actor.get();
}
// Special case if shards_ was not yet initialized.
// This can happen briefly on node startup.
return shards_[ShardIdFull{masterchainId}].actor.get();
}
td::actor::ActorId<FullNodeShard> FullNodeImpl::get_shard(AccountIdPrefixFull dst) {
return get_shard(shard_prefix(dst, 60));
return get_shard(shard_prefix(dst, max_shard_pfx_len));
}
void FullNodeImpl::got_key_block_config(td::Ref<ConfigHolder> config) {
@ -407,7 +492,9 @@ void FullNodeImpl::got_key_block_config(td::Ref<ConfigHolder> config) {
CHECK(all_validators_.size() > 0);
for (auto &shard : shards_) {
td::actor::send_closure(shard.second, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
if (!shard.second.actor.empty()) {
td::actor::send_closure(shard.second.actor, &FullNodeShard::update_validators, all_validators_, sign_cert_by_);
}
}
}
@ -489,9 +576,9 @@ void FullNodeImpl::update_validator_telemetry_collector() {
}
void FullNodeImpl::start_up() {
add_shard(ShardIdFull{masterchainId});
update_shard_actor(ShardIdFull{masterchainId}, true);
if (local_id_.is_zero()) {
if(adnl_id_.is_zero()) {
if (adnl_id_.is_zero()) {
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
local_id_ = pk.compute_short_id();
@ -505,11 +592,9 @@ void FullNodeImpl::start_up() {
void initial_read_complete(BlockHandle handle) override {
td::actor::send_closure(id_, &FullNodeImpl::initial_read_complete, handle);
}
void add_shard(ShardIdFull shard) override {
td::actor::send_closure(id_, &FullNodeImpl::add_shard, shard);
}
void del_shard(ShardIdFull shard) override {
td::actor::send_closure(id_, &FullNodeImpl::del_shard, shard);
void on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor) override {
td::actor::send_closure(id_, &FullNodeImpl::on_new_masterchain_block, std::move(state),
std::move(shards_to_monitor));
}
void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) override {
td::actor::send_closure(id_, &FullNodeImpl::send_ihr_message, dst, std::move(data));
@ -555,10 +640,10 @@ void FullNodeImpl::start_up() {
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, std::string tmp_dir, td::Timestamp timeout,
td::Promise<std::string> promise) override {
td::actor::send_closure(id_, &FullNodeImpl::download_archive, masterchain_seqno, std::move(tmp_dir), 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));
}
void new_key_block(BlockHandle handle) override {
@ -568,16 +653,15 @@ void FullNodeImpl::start_up() {
td::actor::send_closure(id_, &FullNodeImpl::send_validator_telemetry, key, std::move(telemetry));
}
Callback(td::actor::ActorId<FullNodeImpl> id) : id_(id) {
explicit Callback(td::actor::ActorId<FullNodeImpl> id) : id_(id) {
}
private:
td::actor::ActorId<FullNodeImpl> id_;
};
auto P = td::PromiseCreator::lambda([](td::Unit R) {});
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::install_callback,
std::make_unique<Callback>(actor_id(this)), std::move(P));
std::make_unique<Callback>(actor_id(this)), std::move(started_promise_));
}
void FullNodeImpl::update_private_overlays() {
@ -635,7 +719,7 @@ void FullNodeImpl::update_custom_overlay(CustomOverlayInfo &overlay) {
}
}
void FullNodeImpl::send_block_broadcast_to_custom_overlays(const BlockBroadcast& broadcast) {
void FullNodeImpl::send_block_broadcast_to_custom_overlays(const BlockBroadcast &broadcast) {
if (!custom_overlays_sent_broadcasts_.insert(broadcast.block_id).second) {
return;
}
@ -644,11 +728,12 @@ void FullNodeImpl::send_block_broadcast_to_custom_overlays(const BlockBroadcast&
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());
for (auto &[_, private_overlay] : custom_overlays_) {
if (private_overlay.params_.send_shard(broadcast.block_id.shard_full())) {
for (auto &[local_id, actor] : private_overlay.actors_) {
if (private_overlay.params_.block_senders_.contains(local_id)) {
td::actor::send_closure(actor, &FullNodeCustomOverlay::send_broadcast, broadcast.clone());
}
}
}
}
@ -666,12 +751,13 @@ void FullNodeImpl::send_block_candidate_broadcast_to_custom_overlays(const Block
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());
for (auto &[_, private_overlay] : custom_overlays_) {
if (private_overlay.params_.send_shard(block_id.shard_full())) {
for (auto &[local_id, actor] : private_overlay.actors_) {
if (private_overlay.params_.block_senders_.contains(local_id)) {
td::actor::send_closure(actor, &FullNodeCustomOverlay::send_block_candidate, block_id, cc_seqno,
validator_set_hash, data.clone());
}
}
}
}
@ -683,7 +769,8 @@ FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id
td::actor::ActorId<rldp2::Rldp> rldp2, td::actor::ActorId<dht::Dht> dht,
td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root)
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root,
td::Promise<td::Unit> started_promise)
: local_id_(local_id)
, adnl_id_(adnl_id)
, zero_state_file_hash_(zero_state_file_hash)
@ -696,19 +783,19 @@ FullNodeImpl::FullNodeImpl(PublicKeyHash local_id, adnl::AdnlNodeIdShort adnl_id
, validator_manager_(validator_manager)
, client_(client)
, db_root_(db_root)
, started_promise_(std::move(started_promise))
, config_(config) {
}
td::actor::ActorOwn<FullNode> FullNode::create(ton::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,
td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root) {
td::actor::ActorOwn<FullNode> FullNode::create(
ton::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,
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);
adnl, rldp, rldp2, dht, overlays, validator_manager, client, db_root,
std::move(started_promise));
}
FullNodeConfig::FullNodeConfig(const tl_object_ptr<ton_api::engine_validator_fullNodeConfig> &obj)
@ -725,18 +812,27 @@ bool FullNodeConfig::operator!=(const FullNodeConfig &rhs) const {
return !(*this == rhs);
}
bool CustomOverlayParams::send_shard(const ShardIdFull &shard) const {
return sender_shards_.empty() ||
std::any_of(sender_shards_.begin(), sender_shards_.end(),
[&](const ShardIdFull &our_shard) { return shard_intersects(shard, our_shard); });
}
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_;
c.msg_senders_[adnl::AdnlNodeIdShort{node->adnl_id_}] = node->msg_sender_priority_;
}
if (node->block_sender_) {
c.block_senders_.emplace(node->adnl_id_);
}
}
for (const auto &shard : f.sender_shards_) {
c.sender_shards_.push_back(create_shard_id(shard));
}
return c;
}

View file

@ -60,7 +60,9 @@ struct CustomOverlayParams {
std::vector<adnl::AdnlNodeIdShort> nodes_;
std::map<adnl::AdnlNodeIdShort, int> msg_senders_;
std::set<adnl::AdnlNodeIdShort> block_senders_;
std::vector<ShardIdFull> sender_shards_;
bool send_shard(const ShardIdFull& shard) const;
static CustomOverlayParams fetch(const ton_api::engine_validator_customOverlay& f);
};
@ -103,14 +105,12 @@ class FullNode : public td::actor::Actor {
}
enum { broadcast_mode_public = 1, broadcast_mode_private_block = 2, broadcast_mode_custom = 4 };
static td::actor::ActorOwn<FullNode> create(ton::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,
td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root);
static td::actor::ActorOwn<FullNode> create(
ton::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,
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);
};
} // namespace fullnode

View file

@ -44,9 +44,8 @@ class FullNodeImpl : public FullNode {
void add_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) override;
void del_permanent_key(PublicKeyHash key, td::Promise<td::Unit> promise) override;
void sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
td::uint32 expiry_at, td::uint32 max_size,
td::Promise<td::BufferSlice> promise) override;
void sign_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key, td::uint32 expiry_at,
td::uint32 max_size, td::Promise<td::BufferSlice> promise) override;
void import_shard_overlay_certificate(ShardIdFull shard_id, PublicKeyHash signed_key,
std::shared_ptr<ton::overlay::Certificate> cert,
td::Promise<td::Unit> promise) override;
@ -57,8 +56,7 @@ class FullNodeImpl : public FullNode {
void add_custom_overlay(CustomOverlayParams params, td::Promise<td::Unit> promise) override;
void del_custom_overlay(std::string name, td::Promise<td::Unit> promise) override;
void add_shard(ShardIdFull shard);
void del_shard(ShardIdFull shard);
void on_new_masterchain_block(td::Ref<MasterchainState> state, std::set<ShardIdFull> shards_to_monitor);
void sync_completed();
@ -79,8 +77,8 @@ class FullNodeImpl : public FullNode {
void download_block_proof_link(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::BufferSlice> promise);
void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout, td::Promise<std::vector<BlockIdExt>> promise);
void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
td::Promise<std::string> promise);
void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise);
void got_key_block_config(td::Ref<ConfigHolder> config);
void new_key_block(BlockHandle handle);
@ -99,17 +97,26 @@ class FullNodeImpl : public FullNode {
td::actor::ActorId<rldp::Rldp> rldp, td::actor::ActorId<rldp2::Rldp> rldp2,
td::actor::ActorId<dht::Dht> dht, td::actor::ActorId<overlay::Overlays> overlays,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root);
td::actor::ActorId<adnl::AdnlExtClient> client, std::string db_root,
td::Promise<td::Unit> started_promise);
private:
struct ShardInfo {
td::actor::ActorOwn<FullNodeShard> actor;
bool active = false;
td::Timestamp delete_at = td::Timestamp::never();
};
void update_shard_actor(ShardIdFull shard, bool active);
PublicKeyHash local_id_;
adnl::AdnlNodeIdShort adnl_id_;
FileHash zero_state_file_hash_;
td::actor::ActorId<FullNodeShard> get_shard(AccountIdPrefixFull dst);
td::actor::ActorId<FullNodeShard> get_shard(ShardIdFull dst);
std::map<ShardIdFull, td::actor::ActorOwn<FullNodeShard>> shards_;
td::actor::ActorId<FullNodeShard> get_shard(ShardIdFull shard);
std::map<ShardIdFull, ShardInfo> shards_;
int wc_monitor_min_split_ = 0;
td::actor::ActorId<keyring::Keyring> keyring_;
td::actor::ActorId<adnl::Adnl> adnl_;
@ -127,6 +134,8 @@ class FullNodeImpl : public FullNode {
std::map<PublicKeyHash, adnl::AdnlNodeIdShort> current_validators_;
std::set<PublicKeyHash> local_keys_;
td::Promise<td::Unit> started_promise_;
FullNodeConfig config_;
std::map<PublicKeyHash, td::actor::ActorOwn<FullNodePrivateBlockOverlay>> private_block_overlays_;

View file

@ -40,8 +40,7 @@ set(TON_VALIDATOR_SOURCE
signature-set.hpp
top-shard-descr.hpp
validate-query.hpp
validator-set.hpp
)
validator-set.hpp)
add_library(ton_validator STATIC ${TON_VALIDATOR_SOURCE})

View file

@ -160,6 +160,9 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
return td::make_ref<ConfigHolderQ>(config_);
}
}
block::WorkchainSet get_workchain_list() const override {
return config_ ? config_->get_workchain_list() : block::WorkchainSet();
}
private:
ZeroStateIdExt zerostate_id_;

View file

@ -17,6 +17,7 @@
Copyright 2019-2020 Telegram Systems LLP
*/
#include "import-db-slice.hpp"
#include "validator/db/fileref.hpp"
#include "td/utils/overloaded.h"
#include "validator/fabric.h"
@ -26,35 +27,91 @@
#include "ton/ton-io.hpp"
#include "downloaders/download-state.hpp"
#include <delay.h>
namespace ton {
namespace validator {
ArchiveImporter::ArchiveImporter(std::string path, td::Ref<MasterchainState> state, BlockSeqno shard_client_seqno,
ArchiveImporter::ArchiveImporter(std::string db_root, td::Ref<MasterchainState> state, BlockSeqno shard_client_seqno,
td::Ref<ValidatorManagerOptions> opts, td::actor::ActorId<ValidatorManager> manager,
td::Promise<std::vector<BlockSeqno>> promise)
: path_(std::move(path))
, state_(std::move(state))
std::vector<std::string> to_import_files,
td::Promise<std::pair<BlockSeqno, BlockSeqno>> promise)
: db_root_(std::move(db_root))
, last_masterchain_state_(std::move(state))
, shard_client_seqno_(shard_client_seqno)
, start_import_seqno_(shard_client_seqno + 1)
, opts_(std::move(opts))
, manager_(manager)
, to_import_files_(std::move(to_import_files))
, use_imported_files_(!to_import_files_.empty())
, promise_(std::move(promise)) {
}
void ArchiveImporter::start_up() {
auto R = Package::open(path_, false, false);
if (R.is_error()) {
abort_query(R.move_as_error());
if (use_imported_files_) {
LOG(INFO) << "Importing archive for masterchain seqno #" << start_import_seqno_ << " from disk";
for (const std::string& path : to_import_files_) {
LOG(INFO) << "Importing file from disk " << path;
td::Status S = process_package(path, true);
if (S.is_error()) {
LOG(INFO) << "Error processing package " << path << ": " << S;
}
}
files_to_cleanup_.clear();
processed_mc_archive();
return;
}
package_ = std::make_shared<Package>(R.move_as_ok());
LOG(INFO) << "Importing archive for masterchain seqno #" << start_import_seqno_ << " from net";
td::actor::send_closure(manager_, &ValidatorManager::send_download_archive_request, start_import_seqno_,
ShardIdFull{masterchainId}, db_root_ + "/tmp/", td::Timestamp::in(3600.0),
[SelfId = actor_id(this)](td::Result<std::string> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ArchiveImporter::abort_query, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &ArchiveImporter::downloaded_mc_archive, R.move_as_ok());
}
});
}
bool fail = false;
package_->iterate([&](std::string filename, td::BufferSlice data, td::uint64 offset) -> bool {
void ArchiveImporter::downloaded_mc_archive(std::string path) {
td::Status S = process_package(path, true);
if (S.is_error()) {
abort_query(std::move(S));
return;
}
processed_mc_archive();
}
void ArchiveImporter::processed_mc_archive() {
if (masterchain_blocks_.empty()) {
LOG(DEBUG) << "No masterhchain blocks in archive";
last_masterchain_seqno_ = last_masterchain_state_->get_seqno();
checked_all_masterchain_blocks();
return;
}
auto seqno = masterchain_blocks_.begin()->first;
LOG(DEBUG) << "First mc seqno in archive = " << seqno;
if (seqno > last_masterchain_state_->get_seqno() + 1) {
abort_query(td::Status::Error(ErrorCode::notready, "too big first masterchain seqno"));
return;
}
check_masterchain_block(seqno);
}
td::Status ArchiveImporter::process_package(std::string path, bool with_masterchain) {
LOG(DEBUG) << "Processing package " << path << " (with_masterchain=" << with_masterchain << ")";
files_to_cleanup_.push_back(path);
TRY_RESULT(p, Package::open(path, false, false));
auto package = std::make_shared<Package>(std::move(p));
td::Status S = td::Status::OK();
package->iterate([&](std::string filename, td::BufferSlice, td::uint64 offset) -> bool {
auto F = FileReference::create(filename);
if (F.is_error()) {
abort_query(F.move_as_error());
fail = true;
S = F.move_as_error();
return false;
}
auto f = F.move_as_ok();
@ -79,33 +136,26 @@ void ArchiveImporter::start_up() {
ignore = false;
is_proof = false;
},
[&](const auto &p) { ignore = true; }));
[&](const auto &) { ignore = true; }));
if (!ignore) {
blocks_[b][is_proof ? 0 : 1] = offset;
if (!ignore && (with_masterchain || !b.is_masterchain())) {
if (is_proof) {
blocks_[b].proof_pkg = package;
blocks_[b].proof_offset = offset;
} else {
blocks_[b].data_pkg = package;
blocks_[b].data_offset = offset;
}
if (b.is_masterchain()) {
masterchain_blocks_[b.seqno()] = b;
last_masterchain_seqno_ = std::max(last_masterchain_seqno_, b.seqno());
} else {
have_shard_blocks_ = true;
}
}
return true;
});
if (fail) {
return;
}
if (masterchain_blocks_.size() == 0) {
abort_query(td::Status::Error(ErrorCode::notready, "archive does not contain any masterchain blocks"));
return;
}
auto seqno = masterchain_blocks_.begin()->first;
if (seqno > state_->get_seqno() + 1) {
abort_query(td::Status::Error(ErrorCode::notready, "too big first masterchain seqno"));
return;
}
check_masterchain_block(seqno);
return S;
}
void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
@ -115,17 +165,17 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
abort_query(td::Status::Error(ErrorCode::notready, "no new blocks"));
return;
}
checked_all_masterchain_blocks(seqno - 1);
checked_all_masterchain_blocks();
return;
}
while (seqno <= state_->get_block_id().seqno()) {
if (seqno < state_->get_block_id().seqno()) {
if (!state_->check_old_mc_block_id(it->second)) {
while (seqno <= last_masterchain_state_->get_block_id().seqno()) {
if (seqno < last_masterchain_state_->get_block_id().seqno()) {
if (!last_masterchain_state_->check_old_mc_block_id(it->second)) {
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad old masterchain block id"));
return;
}
} else {
if (state_->get_block_id() != it->second) {
if (last_masterchain_state_->get_block_id() != it->second) {
abort_query(td::Status::Error(ErrorCode::protoviolation, "bad old masterchain block id"));
return;
}
@ -133,18 +183,27 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
seqno++;
it = masterchain_blocks_.find(seqno);
if (it == masterchain_blocks_.end()) {
checked_all_masterchain_blocks(seqno - 1);
checked_all_masterchain_blocks();
return;
}
}
if (seqno != state_->get_block_id().seqno() + 1) {
LOG(DEBUG) << "Checking masterchain block #" << seqno;
if (seqno != last_masterchain_state_->get_block_id().seqno() + 1) {
abort_query(td::Status::Error(ErrorCode::protoviolation, "hole in masterchain seqno"));
return;
}
auto it2 = blocks_.find(it->second);
CHECK(it2 != blocks_.end());
if (!it2->second.proof_pkg) {
abort_query(td::Status::Error(ErrorCode::protoviolation, "no masterchain block proof"));
return;
}
if (!it2->second.data_pkg) {
abort_query(td::Status::Error(ErrorCode::protoviolation, "no masterchain block data"));
return;
}
auto R1 = package_->read(it2->second[0]);
auto R1 = it2->second.proof_pkg->read(it2->second.proof_offset);
if (R1.is_error()) {
abort_query(R1.move_as_error());
return;
@ -156,7 +215,7 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
return;
}
auto R2 = package_->read(it2->second[1]);
auto R2 = it2->second.data_pkg->read(it2->second.data_offset);
if (R2.is_error()) {
abort_query(R2.move_as_error());
return;
@ -175,7 +234,7 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
auto proof = proofR.move_as_ok();
auto data = dataR.move_as_ok();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id = state_->get_block_id(),
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), id = last_masterchain_state_->get_block_id(),
data](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ArchiveImporter::abort_query, R.move_as_error());
@ -191,11 +250,12 @@ void ArchiveImporter::check_masterchain_block(BlockSeqno seqno) {
td::actor::send_closure(SelfId, &ArchiveImporter::checked_masterchain_proof, std::move(handle), std::move(data));
});
run_check_proof_query(it->second, std::move(proof), manager_, td::Timestamp::in(2.0), std::move(P), state_,
opts_->is_hardfork(it->second));
run_check_proof_query(it->second, std::move(proof), manager_, td::Timestamp::in(2.0), std::move(P),
last_masterchain_state_, opts_->is_hardfork(it->second));
}
void ArchiveImporter::checked_masterchain_proof(BlockHandle handle, td::Ref<BlockData> data) {
LOG(DEBUG) << "Checked proof for masterchain block #" << handle->id().seqno();
CHECK(data.not_null());
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Unit> R) {
R.ensure();
@ -205,6 +265,7 @@ void ArchiveImporter::checked_masterchain_proof(BlockHandle handle, td::Ref<Bloc
}
void ArchiveImporter::applied_masterchain_block(BlockHandle handle) {
LOG(DEBUG) << "Applied masterchain block #" << handle->id().seqno();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
R.ensure();
td::actor::send_closure(SelfId, &ArchiveImporter::got_new_materchain_state,
@ -214,22 +275,87 @@ void ArchiveImporter::applied_masterchain_block(BlockHandle handle) {
}
void ArchiveImporter::got_new_materchain_state(td::Ref<MasterchainState> state) {
state_ = std::move(state);
check_masterchain_block(state_->get_block_id().seqno() + 1);
last_masterchain_state_ = std::move(state);
imported_any_ = true;
check_masterchain_block(last_masterchain_state_->get_block_id().seqno() + 1);
}
void ArchiveImporter::checked_all_masterchain_blocks(BlockSeqno seqno) {
check_next_shard_client_seqno(shard_client_seqno_ + 1);
void ArchiveImporter::checked_all_masterchain_blocks() {
LOG(DEBUG) << "Done importing masterchain blocks. Last block seqno = " << last_masterchain_seqno_;
if (start_import_seqno_ > last_masterchain_state_->get_seqno()) {
abort_query(td::Status::Error("no new masterchain blocks were imported"));
return;
}
BlockIdExt block_id;
CHECK(last_masterchain_state_->get_old_mc_block_id(start_import_seqno_, block_id));
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db_short, block_id,
[SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
R.ensure();
td::Ref<MasterchainState> state{R.move_as_ok()};
td::actor::send_closure(SelfId, &ArchiveImporter::download_shard_archives,
std::move(state));
});
}
void ArchiveImporter::download_shard_archives(td::Ref<MasterchainState> start_state) {
start_state_ = start_state;
td::uint32 monitor_min_split = start_state->monitor_min_split_depth(basechainId);
LOG(DEBUG) << "Monitor min split = " << monitor_min_split;
// If monitor_min_split == 0, we use the old archive format (packages are not separated by shard)
// If masterchain package has shard blocks then it's old archive format, don't need to download shards
if (monitor_min_split > 0 && !have_shard_blocks_ && !use_imported_files_) {
for (td::uint64 i = 0; i < (1ULL << monitor_min_split); ++i) {
ShardIdFull shard_prefix{basechainId, (i * 2 + 1) << (64 - monitor_min_split - 1)};
if (opts_->need_monitor(shard_prefix, start_state)) {
++pending_shard_archives_;
LOG(DEBUG) << "Downloading shard archive #" << start_import_seqno_ << " " << shard_prefix.to_str();
download_shard_archive(shard_prefix);
}
}
} else {
LOG(DEBUG) << "Skip downloading shard archives";
}
if (pending_shard_archives_ == 0) {
check_next_shard_client_seqno(shard_client_seqno_ + 1);
}
}
void ArchiveImporter::download_shard_archive(ShardIdFull shard_prefix) {
td::actor::send_closure(
manager_, &ValidatorManager::send_download_archive_request, start_import_seqno_, shard_prefix, db_root_ + "/tmp/",
td::Timestamp::in(3600.0),
[SelfId = actor_id(this), seqno = start_import_seqno_, shard_prefix](td::Result<std::string> R) {
if (R.is_error()) {
LOG(WARNING) << "Failed to download archive slice #" << seqno << " for shard " << shard_prefix.to_str();
delay_action(
[=]() { td::actor::send_closure(SelfId, &ArchiveImporter::download_shard_archive, shard_prefix); },
td::Timestamp::in(2.0));
} else {
LOG(DEBUG) << "Downloaded shard archive #" << seqno << " " << shard_prefix.to_str();
td::actor::send_closure(SelfId, &ArchiveImporter::downloaded_shard_archive, R.move_as_ok());
}
});
}
void ArchiveImporter::downloaded_shard_archive(std::string path) {
td::Status S = process_package(path, false);
if (S.is_error()) {
LOG(INFO) << "Error processing package: " << S;
}
--pending_shard_archives_;
if (pending_shard_archives_ == 0) {
check_next_shard_client_seqno(shard_client_seqno_ + 1);
}
}
void ArchiveImporter::check_next_shard_client_seqno(BlockSeqno seqno) {
if (seqno > state_->get_seqno()) {
if (seqno > last_masterchain_state_->get_seqno() || seqno > last_masterchain_seqno_) {
finish_query();
} else if (seqno == state_->get_seqno()) {
got_masterchain_state(state_);
} else if (seqno == last_masterchain_state_->get_seqno()) {
got_masterchain_state(last_masterchain_state_);
} else {
BlockIdExt b;
bool f = state_->get_old_mc_block_id(seqno, b);
bool f = last_masterchain_state_->get_old_mc_block_id(seqno, b);
CHECK(f);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
R.ensure();
@ -241,33 +367,38 @@ void ArchiveImporter::check_next_shard_client_seqno(BlockSeqno seqno) {
}
void ArchiveImporter::got_masterchain_state(td::Ref<MasterchainState> state) {
if (state->get_seqno() != start_import_seqno_ && state->is_key_state()) {
finish_query();
return;
}
LOG(DEBUG) << "Applying shard client seqno " << state->get_seqno();
auto s = state->get_shards();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), seqno = state->get_seqno()](td::Result<td::Unit> R) {
td::MultiPromise mp;
auto ig = mp.init_guard();
for (auto &shard : s) {
if (opts_->need_monitor(shard->shard(), state)) {
apply_shard_block(shard->top_block_id(), state->get_block_id(), ig.get_promise());
}
}
ig.add_promise([SelfId = actor_id(this), seqno = state->get_seqno()](td::Result<td::Unit> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &ArchiveImporter::abort_query, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &ArchiveImporter::checked_shard_client_seqno, seqno);
}
});
td::MultiPromise mp;
auto ig = mp.init_guard();
ig.add_promise(std::move(P));
for (auto &shard : s) {
apply_shard_block(shard->top_block_id(), state->get_block_id(), ig.get_promise());
}
}
void ArchiveImporter::checked_shard_client_seqno(BlockSeqno seqno) {
CHECK(shard_client_seqno_ + 1 == seqno);
shard_client_seqno_++;
imported_any_ = true;
check_next_shard_client_seqno(seqno + 1);
}
void ArchiveImporter::apply_shard_block(BlockIdExt block_id, BlockIdExt masterchain_block_id,
td::Promise<td::Unit> promise) {
LOG(DEBUG) << "Applying shard block " << block_id.id.to_str();
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), masterchain_block_id, promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
R.ensure();
@ -286,7 +417,7 @@ void ArchiveImporter::apply_shard_block_cont1(BlockHandle handle, BlockIdExt mas
if (handle->id().seqno() == 0) {
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise)](td::Result<td::Ref<ShardState>> R) mutable { promise.set_value(td::Unit()); });
[promise = std::move(promise)](td::Result<td::Ref<ShardState>>) mutable { promise.set_value(td::Unit()); });
td::actor::create_actor<DownloadShardState>("downloadstate", handle->id(), masterchain_block_id, 2, manager_,
td::Timestamp::in(3600), std::move(P))
.release();
@ -294,12 +425,13 @@ void ArchiveImporter::apply_shard_block_cont1(BlockHandle handle, BlockIdExt mas
}
auto it = blocks_.find(handle->id());
if (it == blocks_.end()) {
promise.set_error(td::Status::Error(ErrorCode::notready, PSTRING() << "no proof for shard block " << handle->id()));
if (it == blocks_.end() || !it->second.proof_pkg || !it->second.data_pkg) {
promise.set_error(
td::Status::Error(ErrorCode::notready, PSTRING() << "no data/proof for shard block " << handle->id()));
return;
}
TRY_RESULT_PROMISE(promise, data, package_->read(it->second[0]));
TRY_RESULT_PROMISE(promise, proof, create_proof_link(handle->id(), std::move(data.second)));
TRY_RESULT_PROMISE(promise, proof_data, it->second.proof_pkg->read(it->second.proof_offset));
TRY_RESULT_PROMISE(promise, proof, create_proof_link(handle->id(), std::move(proof_data.second)));
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle, masterchain_block_id,
promise = std::move(promise)](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
@ -345,8 +477,8 @@ void ArchiveImporter::apply_shard_block_cont2(BlockHandle handle, BlockIdExt mas
void ArchiveImporter::apply_shard_block_cont3(BlockHandle handle, BlockIdExt masterchain_block_id,
td::Promise<td::Unit> promise) {
auto it = blocks_.find(handle->id());
CHECK(it != blocks_.end());
TRY_RESULT_PROMISE(promise, data, package_->read(it->second[1]));
CHECK(it != blocks_.end() && it->second.data_pkg);
TRY_RESULT_PROMISE(promise, data, it->second.data_pkg->read(it->second.data_offset));
if (sha256_bits256(data.second.as_slice()) != handle->id().file_hash) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "bad block file hash"));
return;
@ -367,6 +499,7 @@ void ArchiveImporter::check_shard_block_applied(BlockIdExt block_id, td::Promise
if (!handle->is_applied()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not applied"));
} else {
LOG(DEBUG) << "Applied shard block " << handle->id().id.to_str();
promise.set_value(td::Unit());
}
}
@ -375,13 +508,24 @@ void ArchiveImporter::check_shard_block_applied(BlockIdExt block_id, td::Promise
}
void ArchiveImporter::abort_query(td::Status error) {
LOG(INFO) << error;
if (!imported_any_) {
for (const std::string &f : files_to_cleanup_) {
td::unlink(f).ignore();
}
promise_.set_error(std::move(error));
return;
}
LOG(INFO) << "Archive import: " << error;
finish_query();
}
void ArchiveImporter::finish_query() {
for (const std::string &f : files_to_cleanup_) {
td::unlink(f).ignore();
}
if (promise_) {
promise_.set_value(
std::vector<BlockSeqno>{state_->get_seqno(), std::min<BlockSeqno>(state_->get_seqno(), shard_client_seqno_)});
promise_.set_value({last_masterchain_state_->get_seqno(),
std::min<BlockSeqno>(last_masterchain_state_->get_seqno(), shard_client_seqno_)});
}
stop();
}

View file

@ -19,6 +19,7 @@
#pragma once
#include "td/actor/actor.h"
#include "td/utils/port/path.h"
#include "validator/interfaces/validator-manager.h"
#include "validator/db/package.hpp"
@ -28,19 +29,27 @@ namespace validator {
class ArchiveImporter : public td::actor::Actor {
public:
ArchiveImporter(std::string path, td::Ref<MasterchainState> state, BlockSeqno shard_client_seqno,
ArchiveImporter(std::string db_root, td::Ref<MasterchainState> state, BlockSeqno shard_client_seqno,
td::Ref<ValidatorManagerOptions> opts, td::actor::ActorId<ValidatorManager> manager,
td::Promise<std::vector<BlockSeqno>> promise);
std::vector<std::string> to_import_files, td::Promise<std::pair<BlockSeqno, BlockSeqno>> promise);
void start_up() override;
void abort_query(td::Status error);
void finish_query();
void downloaded_mc_archive(std::string path);
td::Status process_package(std::string path, bool with_masterchain);
void processed_mc_archive();
void check_masterchain_block(BlockSeqno seqno);
void checked_masterchain_proof(BlockHandle handle, td::Ref<BlockData> data);
void applied_masterchain_block(BlockHandle handle);
void got_new_materchain_state(td::Ref<MasterchainState> state);
void checked_all_masterchain_blocks(BlockSeqno seqno);
void checked_all_masterchain_blocks();
void download_shard_archives(td::Ref<MasterchainState> start_state);
void download_shard_archive(ShardIdFull shard_prefix);
void downloaded_shard_archive(std::string path);
void check_next_shard_client_seqno(BlockSeqno seqno);
void checked_shard_client_seqno(BlockSeqno seqno);
@ -52,19 +61,36 @@ class ArchiveImporter : public td::actor::Actor {
void check_shard_block_applied(BlockIdExt block_id, td::Promise<td::Unit> promise);
private:
std::string path_;
td::Ref<MasterchainState> state_;
std::string db_root_;
td::Ref<MasterchainState> last_masterchain_state_;
BlockSeqno shard_client_seqno_;
BlockSeqno start_import_seqno_;
td::Ref<ValidatorManagerOptions> opts_;
std::shared_ptr<Package> package_;
td::actor::ActorId<ValidatorManager> manager_;
td::Promise<std::vector<BlockSeqno>> promise_;
std::vector<std::string> to_import_files_;
bool use_imported_files_;
td::Promise<std::pair<BlockSeqno, BlockSeqno>> promise_;
std::map<BlockSeqno, BlockIdExt> masterchain_blocks_;
std::map<BlockIdExt, std::array<td::uint64, 2>> blocks_;
BlockSeqno last_masterchain_seqno_ = 0;
struct BlockInfo {
std::shared_ptr<Package> data_pkg;
td::uint64 data_offset = 0;
std::shared_ptr<Package> proof_pkg;
td::uint64 proof_offset = 0;
};
std::map<BlockIdExt, BlockInfo> blocks_;
td::Ref<MasterchainState> start_state_;
size_t pending_shard_archives_ = 0;
bool imported_any_ = false;
bool have_shard_blocks_ = false;
std::vector<std::string> files_to_cleanup_;
};
} // namespace validator

View file

@ -117,12 +117,18 @@ class Db : public td::actor::Actor {
virtual void check_key_block_proof_exists(BlockIdExt block_id, td::Promise<bool> promise) = 0;
virtual void check_key_block_proof_link_exists(BlockIdExt block_id, td::Promise<bool> promise) = 0;
virtual void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) = 0;
virtual void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
td::Promise<td::uint64> promise) = 0;
virtual void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
td::Promise<td::BufferSlice> promise) = 0;
virtual void set_async_mode(bool mode, td::Promise<td::Unit> promise) = 0;
virtual void run_gc(UnixTime mc_ts, UnixTime gc_ts, UnixTime archive_ttl) = 0;
virtual void add_persistent_state_description(td::Ref<PersistentStateDescription> desc,
td::Promise<td::Unit> promise) = 0;
virtual void get_persistent_state_descriptions(
td::Promise<std::vector<td::Ref<PersistentStateDescription>>> promise) = 0;
};
} // namespace validator

View file

@ -84,6 +84,7 @@ class MasterchainState : virtual public ShardState {
ton::LogicalTime* end_lt = nullptr) const = 0;
virtual bool check_old_mc_block_id(const ton::BlockIdExt& blkid, bool strict = false) const = 0;
virtual td::Result<td::Ref<ConfigHolder>> get_config_holder() const = 0;
virtual block::WorkchainSet get_workchain_list() const = 0;
virtual td::Status prepare() {
return td::Status::OK();
}

View file

@ -66,6 +66,8 @@ using ValidateCandidateResult = td::Variant<UnixTime, CandidateReject>;
class ValidatorManager : public ValidatorManagerInterface {
public:
virtual void init_last_masterchain_state(td::Ref<MasterchainState> state) {
}
virtual void set_block_state(BlockHandle handle, td::Ref<ShardState> state,
td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void get_cell_db_reader(td::Promise<std::shared_ptr<vm::CellDbReader>> promise) = 0;
@ -75,10 +77,6 @@ class ValidatorManager : public ValidatorManagerInterface {
std::function<td::Status(td::FileFd&)> write_data,
td::Promise<td::Unit> promise) = 0;
virtual void store_zero_state_file(BlockIdExt block_id, td::BufferSlice state, td::Promise<td::Unit> promise) = 0;
virtual void wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void wait_block_state_short(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void set_block_data(BlockHandle handle, td::Ref<BlockData> data, td::Promise<td::Unit> promise) = 0;
virtual void wait_block_data(BlockHandle handle, td::uint32 priority, td::Timestamp,
@ -148,10 +146,11 @@ class ValidatorManager : public ValidatorManagerInterface {
virtual void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) = 0;
virtual void send_block_broadcast(BlockBroadcast broadcast, int mode) = 0;
virtual void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) = 0;
virtual void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
virtual void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) = 0;
virtual void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) = 0;
virtual void subscribe_to_shard(ShardIdFull shard) = 0;
virtual void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) = 0;
virtual void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) = 0;
@ -212,6 +211,8 @@ class ValidatorManager : public ValidatorManagerInterface {
virtual void record_validate_query_stats(BlockIdExt block_id, double work_time, double cpu_work_time) {
}
virtual void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) = 0;
static bool is_persistent_state(UnixTime ts, UnixTime prev_ts) {
return ts / (1 << 17) != prev_ts / (1 << 17);
}

View file

@ -265,11 +265,13 @@ class ValidatorManagerImpl : public ValidatorManager {
}
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override {
}
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) override {
UNREACHABLE();
}
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
void subscribe_to_shard(ShardIdFull shard) override {
}
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override {
UNREACHABLE();
@ -285,7 +287,8 @@ class ValidatorManagerImpl : public ValidatorManager {
promise.set_error(td::Status::Error(ErrorCode::error, "download disabled"));
}
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) override {
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
td::Promise<td::uint64> promise) override {
UNREACHABLE();
}
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
@ -402,8 +405,8 @@ class ValidatorManagerImpl : public ValidatorManager {
}
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise) override {
if (queue_size_counter_.empty()) {
queue_size_counter_ =
td::actor::create_actor<QueueSizeCounter>("queuesizecounter", td::Ref<MasterchainState>{}, actor_id(this));
queue_size_counter_ = td::actor::create_actor<QueueSizeCounter>("queuesizecounter", td::Ref<MasterchainState>{},
opts_, actor_id(this));
}
td::actor::send_closure(queue_size_counter_, &QueueSizeCounter::get_queue_size, block_id, std::move(promise));
}
@ -437,6 +440,8 @@ class ValidatorManagerImpl : public ValidatorManager {
td::Promise<tl_object_ptr<lite_api::liteServer_nonfinal_validatorGroups>> promise) override {
promise.set_result(td::Status::Error("not implemented"));
}
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) override {
}
void update_options(td::Ref<ValidatorManagerOptions> opts) override {
opts_ = std::move(opts);

View file

@ -20,6 +20,7 @@
#include "interfaces/validator-manager.h"
#include "interfaces/db.h"
#include "ton/ton-types.h"
#include "validator-group.hpp"
#include "manager-init.h"
#include "manager-hardfork.h"
@ -334,6 +335,10 @@ class ValidatorManagerImpl : public ValidatorManager {
}
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override {
}
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) override {
UNREACHABLE();
}
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override {
UNREACHABLE();
@ -341,8 +346,6 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override {
UNREACHABLE();
}
void subscribe_to_shard(ShardIdFull shard) override {
}
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override {
UNREACHABLE();
@ -358,7 +361,8 @@ class ValidatorManagerImpl : public ValidatorManager {
promise.set_error(td::Status::Error(ErrorCode::error, "download disabled"));
}
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) override {
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
td::Promise<td::uint64> promise) override {
UNREACHABLE();
}
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
@ -466,8 +470,8 @@ class ValidatorManagerImpl : public ValidatorManager {
}
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise) override {
if (queue_size_counter_.empty()) {
queue_size_counter_ =
td::actor::create_actor<QueueSizeCounter>("queuesizecounter", td::Ref<MasterchainState>{}, actor_id(this));
queue_size_counter_ = td::actor::create_actor<QueueSizeCounter>("queuesizecounter", td::Ref<MasterchainState>{},
opts_, actor_id(this));
}
td::actor::send_closure(queue_size_counter_, &QueueSizeCounter::get_queue_size, block_id, std::move(promise));
}
@ -504,6 +508,8 @@ class ValidatorManagerImpl : public ValidatorManager {
void update_options(td::Ref<ValidatorManagerOptions> opts) override {
opts_ = std::move(opts);
}
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) override {
}
private:
td::Ref<ValidatorManagerOptions> opts_;

View file

@ -268,6 +268,7 @@ void ValidatorManagerMasterchainReiniter::downloaded_masterchain_state(td::Ref<S
CHECK(handle_->received_state());
CHECK(handle_->is_applied());
LOG(INFO) << "downloaded masterchain state";
td::actor::send_closure(manager_, &ValidatorManager::init_last_masterchain_state, state_);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::downloaded_all_shards);
@ -567,7 +568,7 @@ void ValidatorManagerMasterchainStarter::truncated() {
truncate_shard_next(handle_->id(), ig.get_promise());
auto s = state_->get_shards();
for (auto &shard : s) {
if (opts_->need_monitor(shard->shard())) {
if (opts_->need_monitor(shard->shard(), state_)) {
truncate_shard_next(shard->top_block_id(), ig.get_promise());
}
}

View file

@ -20,11 +20,9 @@
#include "checksum.h"
#include "td/utils/buffer.h"
#include "validator-group.hpp"
#include "adnl/utils.hpp"
#include "downloaders/wait-block-state.hpp"
#include "downloaders/wait-block-state-merge.hpp"
#include "downloaders/wait-block-data.hpp"
#include "validator-group.hpp"
#include "fabric.h"
#include "manager.h"
#include "validate-broadcast.hpp"
@ -202,7 +200,7 @@ void ValidatorManagerImpl::validate_block(ReceivedBlock block, td::Promise<Block
CHECK(blkid.is_masterchain());
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), promise = std::move(promise), id = block.id](td::Result<td::Unit> R) mutable {
[SelfId = actor_id(this), promise = std::move(promise), id = blkid](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
@ -217,12 +215,26 @@ void ValidatorManagerImpl::prevalidate_block(BlockBroadcast broadcast, td::Promi
promise.set_error(td::Status::Error(ErrorCode::notready, "node not started"));
return;
}
if (!need_monitor(broadcast.block_id.shard_full())) {
promise.set_error(td::Status::Error("not monitoring shard"));
return;
}
promise = [SelfId = actor_id(this), promise = std::move(promise), block_id = broadcast.block_id,
cc_seqno = broadcast.catchain_seqno](td::Result<td::Unit> R) mutable {
if (R.is_ok()) {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::validated_block_broadcast, block_id, cc_seqno);
}
promise.set_result(std::move(R));
};
td::actor::create_actor<ValidateBroadcast>("broadcast", std::move(broadcast), last_masterchain_block_handle_,
last_masterchain_state_, last_known_key_block_handle_, actor_id(this),
td::Timestamp::in(2.0), std::move(promise))
.release();
}
void ValidatorManagerImpl::validated_block_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno) {
}
void ValidatorManagerImpl::sync_complete(td::Promise<td::Unit> promise) {
started_ = true;
@ -474,7 +486,7 @@ void ValidatorManagerImpl::new_ihr_message(td::BufferSlice data) {
}
void ValidatorManagerImpl::new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) {
if (!is_validator()) {
if (!is_validator() && !cached_block_candidates_.count(block_id)) {
return;
}
if (!last_masterchain_block_handle_) {
@ -508,37 +520,36 @@ void ValidatorManagerImpl::new_block_candidate(BlockIdExt block_id, td::BufferSl
if (!started_) {
return;
}
if (!need_monitor(block_id.shard_full())) {
VLOG(VALIDATOR_DEBUG) << "dropping block candidate broadcast: not monitoring shard";
return;
}
add_cached_block_candidate(ReceivedBlock{block_id, std::move(data)});
}
void ValidatorManagerImpl::add_shard_block_description(td::Ref<ShardTopBlockDescription> desc) {
if (desc->may_be_valid(last_masterchain_block_handle_, last_masterchain_state_)) {
auto it = shard_blocks_.find(ShardTopBlockDescriptionId{desc->shard(), desc->catchain_seqno()});
if (it != shard_blocks_.end() && desc->block_id().id.seqno <= it->second->block_id().id.seqno) {
VLOG(VALIDATOR_DEBUG) << "dropping duplicate shard block broadcast";
return;
}
shard_blocks_[ShardTopBlockDescriptionId{desc->block_id().shard_full(), desc->catchain_seqno()}] = desc;
VLOG(VALIDATOR_DEBUG) << "new shard block descr for " << desc->block_id();
if (last_masterchain_block_handle_ && last_masterchain_seqno_ > 0 &&
desc->generated_at() < last_masterchain_block_handle_->unix_time() + 60) {
delay_action(
[SelfId = actor_id(this), desc]() {
auto P = td::PromiseCreator::lambda([](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) {
auto S = R.move_as_error();
if (S.code() != ErrorCode::timeout && S.code() != ErrorCode::notready) {
VLOG(VALIDATOR_NOTICE) << "failed to get shard state: " << S;
} else {
VLOG(VALIDATOR_DEBUG) << "failed to get shard state: " << S;
}
}
});
td::actor::send_closure(SelfId, &ValidatorManager::wait_block_state_short, desc->block_id(), 0,
td::Timestamp::in(60.0), std::move(P));
},
td::Timestamp::in(1.0));
}
if (!desc->may_be_valid(last_masterchain_block_handle_, last_masterchain_state_)) {
return;
}
auto it = shard_blocks_.find(ShardTopBlockDescriptionId{desc->shard(), desc->catchain_seqno()});
if (it != shard_blocks_.end() && desc->block_id().id.seqno <= it->second->block_id().id.seqno) {
VLOG(VALIDATOR_DEBUG) << "dropping duplicate shard block broadcast";
return;
}
shard_blocks_[ShardTopBlockDescriptionId{desc->block_id().shard_full(), desc->catchain_seqno()}] = desc;
VLOG(VALIDATOR_DEBUG) << "new shard block descr for " << desc->block_id();
if (need_monitor(desc->block_id().shard_full())) {
auto P = td::PromiseCreator::lambda([](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) {
auto S = R.move_as_error();
if (S.code() != ErrorCode::timeout && S.code() != ErrorCode::notready) {
VLOG(VALIDATOR_NOTICE) << "failed to get shard state: " << S;
} else {
VLOG(VALIDATOR_DEBUG) << "failed to get shard state: " << S;
}
}
});
wait_block_state_short(desc->block_id(), 0, td::Timestamp::in(60.0), std::move(P));
}
}
@ -554,7 +565,7 @@ void ValidatorManagerImpl::add_cached_block_candidate(ReceivedBlock block) {
if (it != wait_block_data_.end()) {
auto r_block = create_block(cached_block_candidates_[id].clone());
if (r_block.is_ok()) {
td::actor::send_closure(it->second.actor_, &WaitBlockData::got_block_data_from_net, r_block.move_as_ok());
td::actor::send_closure(it->second.actor_, &WaitBlockData::loaded_block_data, r_block.move_as_ok());
}
}
}
@ -672,6 +683,10 @@ void ValidatorManagerImpl::run_ext_query(td::BufferSlice data, td::Promise<td::B
void ValidatorManagerImpl::wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::Ref<ShardState>> promise) {
if (last_masterchain_state_.not_null() && !opts_->need_monitor(handle->id().shard_full(), last_masterchain_state_)) {
return promise.set_error(
td::Status::Error(PSTRING() << "not monitoring shard " << handle->id().shard_full().to_str()));
}
auto it0 = block_state_cache_.find(handle->id());
if (it0 != block_state_cache_.end()) {
it0->second.ttl_ = td::Timestamp::in(30.0);
@ -683,9 +698,11 @@ void ValidatorManagerImpl::wait_block_state(BlockHandle handle, td::uint32 prior
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Ref<ShardState>> R) {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::finished_wait_state, handle, std::move(R));
});
auto id = td::actor::create_actor<WaitBlockState>("waitstate", handle, priority, actor_id(this),
td::Timestamp::in(10.0), std::move(P))
.release();
auto id =
td::actor::create_actor<WaitBlockState>("waitstate", handle, priority, actor_id(this),
td::Timestamp::at(timeout.at() + 10.0), std::move(P),
get_block_persistent_state(handle->id()))
.release();
wait_state_[handle->id()].actor_ = id;
it = wait_state_.find(handle->id());
}
@ -717,7 +734,7 @@ void ValidatorManagerImpl::wait_block_data(BlockHandle handle, td::uint32 priori
td::actor::send_closure(SelfId, &ValidatorManagerImpl::finished_wait_data, handle, std::move(R));
});
auto id = td::actor::create_actor<WaitBlockData>("waitdata", handle, priority, actor_id(this),
td::Timestamp::in(10.0), std::move(P))
td::Timestamp::at(timeout.at() + 10.0), false, std::move(P))
.release();
wait_block_data_[handle->id()].actor_ = id;
it = wait_block_data_.find(handle->id());
@ -744,6 +761,10 @@ void ValidatorManagerImpl::wait_block_data_short(BlockIdExt block_id, td::uint32
void ValidatorManagerImpl::wait_block_state_merge(BlockIdExt left_id, BlockIdExt right_id, td::uint32 priority,
td::Timestamp timeout, td::Promise<td::Ref<ShardState>> promise) {
if (last_masterchain_state_.not_null() && !opts_->need_monitor(left_id.shard_full(), last_masterchain_state_)) {
return promise.set_error(
td::Status::Error(PSTRING() << "not monitoring shard " << left_id.shard_full().to_str()));
}
td::actor::create_actor<WaitBlockStateMerge>("merge", left_id, right_id, priority, actor_id(this), timeout,
std::move(promise))
.release();
@ -1128,7 +1149,7 @@ void ValidatorManagerImpl::finished_wait_state(BlockHandle handle, td::Result<td
td::actor::send_closure(SelfId, &ValidatorManagerImpl::finished_wait_state, handle, std::move(R));
});
auto id = td::actor::create_actor<WaitBlockState>("waitstate", handle, X.second, actor_id(this), X.first,
std::move(P))
std::move(P), get_block_persistent_state(handle->id()))
.release();
it->second.actor_ = id;
return;
@ -1158,8 +1179,9 @@ void ValidatorManagerImpl::finished_wait_data(BlockHandle handle, td::Result<td:
td::actor::send_closure(SelfId, &ValidatorManagerImpl::finished_wait_data, handle, std::move(R));
});
auto id =
td::actor::create_actor<WaitBlockData>("waitdata", handle, X.second, actor_id(this), X.first, std::move(P))
.release();
td::actor::create_actor<WaitBlockData>("waitdata", handle, X.second, actor_id(this), X.first, false,
std::move(P))
.release();
it->second.actor_ = id;
return;
}
@ -1617,6 +1639,7 @@ void ValidatorManagerImpl::send_top_shard_block_description(td::Ref<ShardTopBloc
} else {
out_shard_blocks_[ShardTopBlockDescriptionId{desc->block_id().shard_full(), desc->catchain_seqno()}] = desc;
callback_->send_shard_block_info(desc->block_id(), desc->catchain_seqno(), desc->serialize());
add_shard_block_description(desc);
}
}
@ -1629,6 +1652,12 @@ void ValidatorManagerImpl::send_validator_telemetry(PublicKeyHash key,
callback_->send_validator_telemetry(key, std::move(telemetry));
}
void ValidatorManagerImpl::send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix,
std::string tmp_dir, td::Timestamp timeout,
td::Promise<std::string> promise) {
callback_->download_archive(mc_seqno, shard_prefix, std::move(tmp_dir), timeout, std::move(promise));
}
void ValidatorManagerImpl::start_up() {
db_ = create_db_actor(actor_id(this), db_root_, opts_);
actor_stats_ = td::actor::create_actor<td::actor::ActorStats>("actor_stats");
@ -1664,7 +1693,6 @@ void ValidatorManagerImpl::start_up() {
if (fname.substr(fname.size() - 5) != ".pack") {
return;
}
fname = fname.substr(0, fname.size() - 5);
if (fname.substr(0, 8) != "archive.") {
return;
}
@ -1673,13 +1701,18 @@ void ValidatorManagerImpl::start_up() {
while (fname.size() > 1 && fname[0] == '0') {
fname.remove_prefix(1);
}
auto i = fname.find('.');
if (i == td::Slice::npos) {
return;
}
fname = fname.substr(0, i);
auto v = td::to_integer_safe<BlockSeqno>(fname);
if (v.is_error()) {
return;
}
auto pos = v.move_as_ok();
LOG(INFO) << "found archive slice '" << cfname << "' for position " << pos;
to_import_[pos] = std::make_pair(cfname.str(), true);
auto seqno = v.move_as_ok();
LOG(INFO) << "found archive slice '" << cfname << "' for seqno " << seqno;
to_import_[seqno].push_back(cfname.str());
}
});
if (S.is_error()) {
@ -1692,6 +1725,14 @@ void ValidatorManagerImpl::start_up() {
alarm_timestamp().relax(check_waiters_at_);
}
void ValidatorManagerImpl::init_last_masterchain_state(td::Ref<MasterchainState> state) {
if (last_masterchain_state_.not_null()) {
return;
}
last_masterchain_state_ = std::move(state);
update_shard_overlays();
}
void ValidatorManagerImpl::started(ValidatorManagerInitResult R) {
CHECK(R.handle);
CHECK(R.state.not_null());
@ -1730,6 +1771,17 @@ void ValidatorManagerImpl::started(ValidatorManagerInitResult R) {
candidates_buffer_ = td::actor::create_actor<CandidatesBuffer>("candidates-buffer", actor_id(this));
}
init_validator_telemetry();
auto Q = td::PromiseCreator::lambda(
[SelfId = actor_id(this)](td::Result<std::vector<td::Ref<PersistentStateDescription>>> R) {
if (R.is_error()) {
LOG(FATAL) << "db error: " << R.move_as_error();
} else {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::got_persistent_state_descriptions, R.move_as_ok());
}
});
td::actor::send_closure(db_, &Db::get_persistent_state_descriptions, std::move(Q));
update_shard_overlays();
}
void ValidatorManagerImpl::read_gc_list(std::vector<ValidatorSessionId> list) {
@ -1832,61 +1884,35 @@ void ValidatorManagerImpl::download_next_archive() {
}
auto seqno = std::min(last_masterchain_seqno_, shard_client_handle_->id().seqno());
std::vector<std::string> to_import_files;
auto it = to_import_.upper_bound(seqno + 1);
if (it != to_import_.begin()) {
it--;
if (it->second.second) {
it->second.second = false;
downloaded_archive_slice(it->second.first, false);
return;
}
--it;
to_import_files = std::move(it->second);
it->second.clear();
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::string> R) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::pair<BlockSeqno, BlockSeqno>> R) {
if (R.is_error()) {
LOG(INFO) << "failed to download archive slice: " << R.error();
LOG(INFO) << "failed to download and import archive slice: " << R.error();
delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); },
td::Timestamp::in(2.0));
} else {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::downloaded_archive_slice, R.move_as_ok(), true);
td::actor::send_closure(SelfId, &ValidatorManagerImpl::checked_archive_slice, R.ok().first, R.ok().second);
}
});
callback_->download_archive(seqno + 1, db_root_ + "/tmp/", td::Timestamp::in(36000.0), std::move(P));
}
void ValidatorManagerImpl::downloaded_archive_slice(std::string name, bool is_tmp) {
LOG(INFO) << "downloaded archive slice: " << name;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), name, is_tmp](td::Result<std::vector<BlockSeqno>> R) {
if (is_tmp) {
td::unlink(name).ensure();
}
if (R.is_error()) {
LOG(INFO) << "failed to check downloaded archive slice: " << R.error();
delay_action([SelfId]() { td::actor::send_closure(SelfId, &ValidatorManagerImpl::download_next_archive); },
td::Timestamp::in(2.0));
} else {
td::actor::send_closure(SelfId, &ValidatorManagerImpl::checked_archive_slice, R.move_as_ok());
}
});
auto seqno = std::min(last_masterchain_seqno_, shard_client_handle_->id().seqno());
td::actor::create_actor<ArchiveImporter>("archiveimport", name, last_masterchain_state_, seqno, opts_, actor_id(this),
std::move(P))
td::actor::create_actor<ArchiveImporter>("archiveimport", db_root_, last_masterchain_state_, seqno, opts_,
actor_id(this), std::move(to_import_files), std::move(P))
.release();
}
void ValidatorManagerImpl::checked_archive_slice(std::vector<BlockSeqno> seqno) {
CHECK(seqno.size() == 2);
LOG(INFO) << "checked downloaded archive slice: mc_top_seqno=" << seqno[0] << " shard_top_seqno_=" << seqno[1];
CHECK(seqno[0] <= last_masterchain_seqno_);
CHECK(seqno[1] <= last_masterchain_seqno_);
void ValidatorManagerImpl::checked_archive_slice(BlockSeqno new_last_mc_seqno, BlockSeqno new_shard_client_seqno) {
LOG(INFO) << "checked downloaded archive slice: mc_top_seqno=" << new_last_mc_seqno
<< " shard_top_seqno_=" << new_shard_client_seqno;
CHECK(new_last_mc_seqno <= last_masterchain_seqno_);
CHECK(new_shard_client_seqno <= last_masterchain_seqno_);
BlockIdExt b;
if (seqno[1] < last_masterchain_seqno_) {
CHECK(last_masterchain_state_->get_old_mc_block_id(seqno[1], b));
} else {
b = last_masterchain_block_id_;
}
BlockIdExt shard_client_block_id;
CHECK(last_masterchain_state_->get_old_mc_block_id(new_shard_client_seqno, shard_client_block_id));
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), db = db_.get(), client = shard_client_.get()](td::Result<BlockHandle> R) {
@ -1902,7 +1928,7 @@ void ValidatorManagerImpl::checked_archive_slice(std::vector<BlockSeqno> seqno)
});
td::actor::send_closure(db, &Db::get_block_state, std::move(handle), std::move(P));
});
get_block_handle(b, true, std::move(P));
get_block_handle(shard_client_block_id, true, std::move(P));
}
void ValidatorManagerImpl::finish_prestart_sync() {
@ -1939,6 +1965,7 @@ void ValidatorManagerImpl::new_masterchain_block() {
init_validator_telemetry();
}
update_shard_overlays();
update_shards();
update_shard_blocks();
@ -1952,6 +1979,26 @@ void ValidatorManagerImpl::new_masterchain_block() {
}
}
void ValidatorManagerImpl::update_shard_overlays() {
CHECK(last_masterchain_state_.not_null());
std::set<ShardIdFull> shards_to_monitor;
shards_to_monitor.insert(ShardIdFull{masterchainId});
std::set<WorkchainId> workchains;
for (const auto& shard : last_masterchain_state_->get_shards()) {
workchains.insert(shard->shard().workchain);
if (opts_->need_monitor(shard->shard(),last_masterchain_state_)) {
shards_to_monitor.insert(shard->shard());
}
}
for (const auto &[wc, desc] : last_masterchain_state_->get_workchain_list()) {
if (!workchains.count(wc) && desc->active &&
opts_->need_monitor(ShardIdFull{wc, shardIdAll}, last_masterchain_state_)) {
shards_to_monitor.insert(ShardIdFull{wc, shardIdAll});
}
}
callback_->on_new_masterchain_block(last_masterchain_state_, std::move(shards_to_monitor));
}
void ValidatorManagerImpl::update_shards() {
if ((last_masterchain_state_->rotated_all_shards() || last_masterchain_seqno_ == 0) &&
opts_->get_last_fork_masterchain_seqno() <= last_masterchain_seqno_) {
@ -2268,7 +2315,8 @@ td::actor::ActorOwn<ValidatorGroup> ValidatorManagerImpl::create_validator_group
auto validator_id = get_validator(shard, validator_set);
CHECK(!validator_id.is_zero());
auto G = td::actor::create_actor<ValidatorGroup>(
"validatorgroup", shard, validator_id, session_id, validator_set, key_seqno, opts, keyring_, adnl_, rldp_,
PSTRING() << "valgroup" << shard.to_str(), shard, validator_id, session_id, validator_set, key_seqno, opts,
keyring_, adnl_, rldp_,
overlays_, db_root_, actor_id(this), init_session,
opts_->check_unsafe_resync_allowed(validator_set->get_catchain_seqno()), opts_);
return G;
@ -2444,7 +2492,7 @@ void ValidatorManagerImpl::allow_block_state_gc(BlockIdExt block_id, td::Promise
return;
}
auto shards = gc_masterchain_state_->get_shards();
for (auto shard : shards) {
for (const auto &shard : shards) {
if (shard_intersects(shard->shard(), block_id.shard_full())) {
promise.set_result(block_id.id.seqno < shard->top_block_id().id.seqno);
return;
@ -2682,10 +2730,6 @@ void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<Bloc
}
}
void ValidatorManagerImpl::subscribe_to_shard(ShardIdFull shard) {
callback_->add_shard(shard);
}
void ValidatorManagerImpl::update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) {
td::actor::send_closure(db_, &Db::update_async_serializer_state, std::move(state), std::move(promise));
}
@ -2698,12 +2742,13 @@ void ValidatorManagerImpl::try_get_static_file(FileHash file_hash, td::Promise<t
td::actor::send_closure(db_, &Db::try_get_static_file, file_hash, std::move(promise));
}
void ValidatorManagerImpl::get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) {
void ValidatorManagerImpl::get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
td::Promise<td::uint64> promise) {
if (masterchain_seqno > last_masterchain_seqno_) {
promise.set_error(td::Status::Error(ErrorCode::notready, "masterchain seqno too big"));
return;
}
td::actor::send_closure(db_, &Db::get_archive_id, masterchain_seqno, std::move(promise));
td::actor::send_closure(db_, &Db::get_archive_id, masterchain_seqno, shard_prefix, std::move(promise));
}
void ValidatorManagerImpl::get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
@ -2715,10 +2760,13 @@ bool ValidatorManagerImpl::is_validator() {
return temp_keys_.size() > 0 || permanent_keys_.size() > 0;
}
bool ValidatorManagerImpl::validating_masterchain() {
return !get_validator(ShardIdFull(masterchainId),
last_masterchain_state_->get_validator_set(ShardIdFull(masterchainId)))
.is_zero();
}
PublicKeyHash ValidatorManagerImpl::get_validator(ShardIdFull shard, td::Ref<ValidatorSet> val_set) {
if (!opts_->need_validate(shard, val_set->get_catchain_seqno())) {
return PublicKeyHash::zero();
}
for (auto &key : temp_keys_) {
if (val_set->is_validator(key.bits256_value())) {
return key;
@ -3224,10 +3272,15 @@ void ValidatorManagerImpl::get_validator_groups_info_for_litequery(
}
void ValidatorManagerImpl::update_options(td::Ref<ValidatorManagerOptions> opts) {
// Currently options can be updated only to change state_serializer_enabled flag and collator_options
if (!shard_client_.empty()) {
td::actor::send_closure(shard_client_, &ShardClient::update_options, opts);
}
if (!serializer_.empty()) {
td::actor::send_closure(serializer_, &AsyncStateSerializer::update_options, opts);
}
if (!queue_size_counter_.empty()) {
td::actor::send_closure(queue_size_counter_, &QueueSizeCounter::update_options, opts);
}
for (auto &group : validator_groups_) {
td::actor::send_closure(group.second.actor, &ValidatorGroup::update_options, opts);
}
@ -3237,6 +3290,53 @@ void ValidatorManagerImpl::update_options(td::Ref<ValidatorManagerOptions> opts)
opts_ = std::move(opts);
}
void ValidatorManagerImpl::add_persistent_state_description(td::Ref<PersistentStateDescription> desc) {
auto now = (UnixTime)td::Clocks::system();
if (desc->end_time <= now) {
return;
}
td::actor::send_closure(db_, &Db::add_persistent_state_description, desc, [](td::Result<td::Unit>) {});
auto it = persistent_state_descriptions_.begin();
while (it != persistent_state_descriptions_.end()) {
const auto &prev_desc = it->second;
if (prev_desc->end_time <= now) {
for (const BlockIdExt &block_id : prev_desc->shard_blocks) {
persistent_state_blocks_.erase(block_id);
}
it = persistent_state_descriptions_.erase(it);
} else {
++it;
}
}
add_persistent_state_description_impl(std::move(desc));
}
void ValidatorManagerImpl::add_persistent_state_description_impl(td::Ref<PersistentStateDescription> desc) {
if (!persistent_state_descriptions_.emplace(desc->masterchain_id.seqno(), desc).second) {
return;
}
LOG(DEBUG) << "Add persistent state description for mc block " << desc->masterchain_id.to_str()
<< " start_time=" << desc->start_time << " end_time=" << desc->end_time;
for (const BlockIdExt &block_id : desc->shard_blocks) {
persistent_state_blocks_[block_id] = desc;
LOG(DEBUG) << "Persistent state description: shard block " << block_id.to_str();
}
}
void ValidatorManagerImpl::got_persistent_state_descriptions(std::vector<td::Ref<PersistentStateDescription>> descs) {
for (auto &desc : descs) {
add_persistent_state_description_impl(std::move(desc));
}
}
td::Ref<PersistentStateDescription> ValidatorManagerImpl::get_block_persistent_state(BlockIdExt block_id) {
auto it = persistent_state_blocks_.find(block_id);
if (it == persistent_state_blocks_.end()) {
return {};
}
return it->second;
}
td::actor::ActorOwn<ValidatorManagerInterface> ValidatorManagerFactory::create(
td::Ref<ValidatorManagerOptions> opts, std::string db_root, td::actor::ActorId<keyring::Keyring> keyring,
td::actor::ActorId<adnl::Adnl> adnl, td::actor::ActorId<rldp::Rldp> rldp,

View file

@ -189,6 +189,12 @@ class ValidatorManagerImpl : public ValidatorManager {
waiting_.resize(j);
}
};
template <typename ActorT, typename ResType>
struct WaitListCaching : public WaitList<ActorT, ResType> {
bool done_ = false;
ResType result_;
td::Timestamp remove_at_;
};
std::map<BlockIdExt, WaitList<WaitBlockState, td::Ref<ShardState>>> wait_state_;
std::map<BlockIdExt, WaitList<WaitBlockData, td::Ref<BlockData>>> wait_block_data_;
@ -305,6 +311,7 @@ class ValidatorManagerImpl : public ValidatorManager {
std::vector<PerfTimerStats> perf_timer_stats;
void new_masterchain_block();
void update_shard_overlays();
void update_shards();
void update_shard_blocks();
void written_destroyed_validator_sessions(std::vector<td::actor::ActorId<ValidatorGroup>> groups);
@ -323,8 +330,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void applied_hardfork();
void prestart_sync();
void download_next_archive();
void downloaded_archive_slice(std::string name, bool is_tmp);
void checked_archive_slice(std::vector<BlockSeqno> seqno);
void checked_archive_slice(BlockSeqno new_last_mc_seqno, BlockSeqno new_shard_client_seqno);
void finish_prestart_sync();
void completed_prestart_sync();
@ -361,6 +367,7 @@ class ValidatorManagerImpl : public ValidatorManager {
td::Promise<td::Unit> promise) override;
void validate_block(ReceivedBlock block, td::Promise<BlockHandle> promise) override;
void prevalidate_block(BlockBroadcast broadcast, td::Promise<td::Unit> promise) override;
void validated_block_broadcast(BlockIdExt block_id, CatchainSeqno cc_seqno);
//void create_validate_block(BlockId block, td::BufferSlice data, td::Promise<Block> promise) = 0;
void sync_complete(td::Promise<td::Unit> promise) override;
@ -505,10 +512,11 @@ class ValidatorManagerImpl : public ValidatorManager {
void send_top_shard_block_description(td::Ref<ShardTopBlockDescription> desc) override;
void send_block_broadcast(BlockBroadcast broadcast, int mode) override;
void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) override;
void send_download_archive_request(BlockSeqno mc_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) override;
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
void subscribe_to_shard(ShardIdFull shard) override;
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) override;
@ -521,7 +529,7 @@ class ValidatorManagerImpl : public ValidatorManager {
std::move(promise));
}
void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) override;
void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, td::Promise<td::uint64> promise) override;
void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
td::Promise<td::BufferSlice> promise) override;
@ -542,10 +550,12 @@ class ValidatorManagerImpl : public ValidatorManager {
void finished_wait_data(BlockHandle handle, td::Result<td::Ref<BlockData>> R);
void start_up() override;
void init_last_masterchain_state(td::Ref<MasterchainState> state) override;
void started(ValidatorManagerInitResult result);
void read_gc_list(std::vector<ValidatorSessionId> list);
bool is_validator();
bool validating_masterchain();
PublicKeyHash get_validator(ShardIdFull shard, td::Ref<ValidatorSet> val_set);
ValidatorManagerImpl(td::Ref<ValidatorManagerOptions> opts, std::string db_root,
@ -604,14 +614,20 @@ class ValidatorManagerImpl : public ValidatorManager {
void update_options(td::Ref<ValidatorManagerOptions> opts) override;
void add_persistent_state_description(td::Ref<PersistentStateDescription> desc) override;
void get_out_msg_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise) override {
if (queue_size_counter_.empty()) {
if (last_masterchain_state_.is_null()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
return;
}
queue_size_counter_ = td::actor::create_actor<QueueSizeCounter>("queuesizecounter",
last_masterchain_state_, actor_id(this));
queue_size_counter_ =
td::actor::create_actor<QueueSizeCounter>("queuesizecounter", last_masterchain_state_, opts_, actor_id(this));
}
if (!opts_->need_monitor(block_id.shard_full(), last_masterchain_state_)) {
return promise.set_error(
td::Status::Error(PSTRING() << "not monitoring shard " << block_id.shard_full().to_str()));
}
td::actor::send_closure(queue_size_counter_, &QueueSizeCounter::get_queue_size, block_id, std::move(promise));
}
@ -682,7 +698,7 @@ class ValidatorManagerImpl : public ValidatorManager {
td::actor::ActorOwn<AsyncStateSerializer> serializer_;
std::map<BlockSeqno, std::pair<std::string, bool>> to_import_;
std::map<BlockSeqno, std::vector<std::string>> to_import_;
private:
std::unique_ptr<Callback> callback_;
@ -712,7 +728,15 @@ class ValidatorManagerImpl : public ValidatorManager {
return 3 * 10;
}
void got_persistent_state_descriptions(std::vector<td::Ref<PersistentStateDescription>> descs);
void add_persistent_state_description_impl(td::Ref<PersistentStateDescription> desc);
td::Ref<PersistentStateDescription> get_block_persistent_state(BlockIdExt block_id);
private:
bool need_monitor(ShardIdFull shard) const {
return opts_->need_monitor(shard, last_masterchain_state_);
}
std::map<BlockSeqno, WaitList<td::actor::Actor, td::Unit>> shard_client_waiters_;
td::actor::ActorOwn<QueueSizeCounter> queue_size_counter_;
@ -740,6 +764,9 @@ class ValidatorManagerImpl : public ValidatorManager {
std::map<PublicKeyHash, td::actor::ActorOwn<ValidatorTelemetry>> validator_telemetry_;
void init_validator_telemetry();
std::map<BlockSeqno, td::Ref<PersistentStateDescription>> persistent_state_descriptions_;
std::map<BlockIdExt, td::Ref<PersistentStateDescription>> persistent_state_blocks_;
};
} // namespace validator

View file

@ -20,6 +20,8 @@
#include "td/utils/port/path.h"
#include "td/utils/overloaded.h"
#include <ton/ton-tl.hpp>
namespace ton {
namespace validator {
@ -27,12 +29,13 @@ namespace validator {
namespace fullnode {
DownloadArchiveSlice::DownloadArchiveSlice(
BlockSeqno masterchain_seqno, std::string tmp_dir, adnl::AdnlNodeIdShort local_id,
BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir, adnl::AdnlNodeIdShort local_id,
overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from, td::Timestamp timeout,
td::actor::ActorId<ValidatorManagerInterface> validator_manager, td::actor::ActorId<adnl::AdnlSenderInterface> rldp,
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<adnl::Adnl> adnl,
td::actor::ActorId<adnl::AdnlExtClient> client, td::Promise<std::string> promise)
: masterchain_seqno_(masterchain_seqno)
, shard_prefix_(shard_prefix)
, tmp_dir_(std::move(tmp_dir))
, local_id_(local_id)
, overlay_id_(overlay_id)
@ -114,7 +117,13 @@ void DownloadArchiveSlice::got_node_to_download(adnl::AdnlNodeIdShort download_f
}
});
auto q = create_serialize_tl_object<ton_api::tonNode_getArchiveInfo>(masterchain_seqno_);
td::BufferSlice q;
if (shard_prefix_.is_masterchain()) {
q = create_serialize_tl_object<ton_api::tonNode_getArchiveInfo>(masterchain_seqno_);
} else {
q = create_serialize_tl_object<ton_api::tonNode_getShardArchiveInfo>(masterchain_seqno_,
create_tl_shard_id(shard_prefix_));
}
if (client_.empty()) {
td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_,
"get_archive_info", std::move(P), td::Timestamp::in(3.0), std::move(q));
@ -145,7 +154,8 @@ void DownloadArchiveSlice::got_archive_info(td::BufferSlice data) {
}
prev_logged_timer_ = td::Timer();
LOG(INFO) << "downloading archive slice #" << masterchain_seqno_ << " from " << download_from_;
LOG(INFO) << "downloading archive slice #" << masterchain_seqno_ << " " << shard_prefix_.to_str() << " from "
<< download_from_;
get_archive_slice();
}
@ -186,13 +196,15 @@ void DownloadArchiveSlice::got_archive_slice(td::BufferSlice data) {
double elapsed = prev_logged_timer_.elapsed();
if (elapsed > 10.0) {
prev_logged_timer_ = td::Timer();
LOG(INFO) << "downloading archive slice #" << masterchain_seqno_ << ": total=" << offset_ << " ("
LOG(INFO) << "downloading archive slice #" << masterchain_seqno_ << " " << shard_prefix_.to_str()
<< ": total=" << offset_ << " ("
<< td::format::as_size((td::uint64)(double(offset_ - prev_logged_sum_) / elapsed)) << "/s)";
prev_logged_sum_ = offset_;
}
if (data.size() < slice_size()) {
LOG(INFO) << "finished downloading arcrive slice #" << masterchain_seqno_ << ": total=" << offset_;
LOG(INFO) << "finished downloading arcrive slice #" << masterchain_seqno_ << " " << shard_prefix_.to_str()
<< ": total=" << offset_;
finish_query();
} else {
get_archive_slice();

View file

@ -32,8 +32,9 @@ namespace fullnode {
class DownloadArchiveSlice : public td::actor::Actor {
public:
DownloadArchiveSlice(BlockSeqno masterchain_seqno, std::string tmp_dir, adnl::AdnlNodeIdShort local_id,
overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from, td::Timestamp timeout,
DownloadArchiveSlice(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
adnl::AdnlNodeIdShort local_id, overlay::OverlayIdShort overlay_id,
adnl::AdnlNodeIdShort download_from, td::Timestamp timeout,
td::actor::ActorId<ValidatorManagerInterface> validator_manager,
td::actor::ActorId<adnl::AdnlSenderInterface> rldp,
td::actor::ActorId<overlay::Overlays> overlays, td::actor::ActorId<adnl::Adnl> adnl,
@ -55,6 +56,7 @@ class DownloadArchiveSlice : public td::actor::Actor {
private:
BlockSeqno masterchain_seqno_;
ShardIdFull shard_prefix_;
std::string tmp_dir_;
std::string tmp_name_;
td::FileFd fd_;

View file

@ -234,7 +234,9 @@ void QueueSizeCounter::process_top_shard_blocks_cont(td::Ref<MasterchainState> s
last_top_blocks_.clear();
last_top_blocks_.push_back(state->get_block_id());
for (auto &shard : state->get_shards()) {
last_top_blocks_.push_back(shard->top_block_id());
if (opts_->need_monitor(shard->shard(), state)) {
last_top_blocks_.push_back(shard->top_block_id());
}
}
for (const BlockIdExt &block_id : last_top_blocks_) {
get_queue_size_ex_retry(block_id, init, ig.get_promise());

View file

@ -21,16 +21,22 @@ namespace ton::validator {
class QueueSizeCounter : public td::actor::Actor {
public:
QueueSizeCounter(td::Ref<MasterchainState> last_masterchain_state, td::actor::ActorId<ValidatorManager> manager)
: init_masterchain_state_(last_masterchain_state), manager_(std::move(manager)) {
QueueSizeCounter(td::Ref<MasterchainState> last_masterchain_state, td::Ref<ValidatorManagerOptions> opts,
td::actor::ActorId<ValidatorManager> manager)
: init_masterchain_state_(last_masterchain_state), opts_(std::move(opts)), manager_(std::move(manager)) {
}
void start_up() override;
void get_queue_size(BlockIdExt block_id, td::Promise<td::uint64> promise);
void alarm() override;
void update_options(td::Ref<ValidatorManagerOptions> opts) {
opts_ = std::move(opts);
}
private:
td::Ref<MasterchainState> init_masterchain_state_;
td::Ref<ValidatorManagerOptions> opts_;
td::actor::ActorId<ValidatorManager> manager_;
bool simple_mode_ = false;

View file

@ -70,18 +70,13 @@ void ShardClient::got_init_handle_from_db(BlockHandle handle) {
}
void ShardClient::got_init_state_from_db(td::Ref<MasterchainState> state) {
masterchain_state_ = std::move(state);
build_shard_overlays();
masterchain_state_.clear();
saved_to_db();
}
void ShardClient::start_up_init_mode() {
build_shard_overlays();
std::vector<BlockIdExt> shards;
for (const auto& s : masterchain_state_->get_shards()) {
if (opts_->need_monitor(s->shard())) {
if (opts_->need_monitor(s->shard(), masterchain_state_)) {
shards.push_back(s->top_block_id());
}
}
@ -166,7 +161,6 @@ void ShardClient::download_masterchain_state() {
void ShardClient::got_masterchain_block_state(td::Ref<MasterchainState> state) {
masterchain_state_ = std::move(state);
build_shard_overlays();
if (started_) {
apply_all_shards();
}
@ -189,8 +183,10 @@ void ShardClient::apply_all_shards() {
ig.add_promise(std::move(P));
auto vec = masterchain_state_->get_shards();
std::set<WorkchainId> workchains;
for (auto &shard : vec) {
if (opts_->need_monitor(shard->shard())) {
workchains.insert(shard->shard().workchain);
if (opts_->need_monitor(shard->shard(), masterchain_state_)) {
auto Q = td::PromiseCreator::lambda([SelfId = actor_id(this), promise = ig.get_promise(),
shard = shard->shard()](td::Result<td::Ref<ShardState>> R) mutable {
if (R.is_error()) {
@ -200,7 +196,22 @@ void ShardClient::apply_all_shards() {
}
});
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short, shard->top_block_id(),
shard_client_priority(), td::Timestamp::in(600), std::move(Q));
shard_client_priority(), td::Timestamp::in(1500), std::move(Q));
}
}
for (const auto &[wc, desc] : masterchain_state_->get_workchain_list()) {
if (!workchains.count(wc) && desc->active && opts_->need_monitor(ShardIdFull{wc, shardIdAll}, masterchain_state_)) {
auto Q = td::PromiseCreator::lambda([SelfId = actor_id(this), promise = ig.get_promise(),
workchain = wc](td::Result<td::Ref<ShardState>> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error_prefix(PSTRING() << "workchain " << workchain << ": "));
} else {
td::actor::send_closure(SelfId, &ShardClient::downloaded_shard_state, R.move_as_ok(), std::move(promise));
}
});
td::actor::send_closure(manager_, &ValidatorManager::wait_block_state_short,
BlockIdExt{wc, shardIdAll, 0, desc->zerostate_root_hash, desc->zerostate_file_hash},
shard_client_priority(), td::Timestamp::in(1500), std::move(Q));
}
}
}
@ -223,7 +234,6 @@ void ShardClient::new_masterchain_block_notification(BlockHandle handle, td::Ref
masterchain_block_handle_ = std::move(handle);
masterchain_state_ = std::move(state);
waiting_ = false;
build_shard_overlays();
apply_all_shards();
}
@ -244,26 +254,6 @@ void ShardClient::get_processed_masterchain_block_id(td::Promise<BlockIdExt> pro
}
}
void ShardClient::build_shard_overlays() {
auto v = masterchain_state_->get_shards();
for (auto &x : v) {
auto shard = x->shard();
if (opts_->need_monitor(shard)) {
auto d = masterchain_state_->monitor_min_split_depth(shard.workchain);
auto l = shard_prefix_length(shard.shard);
if (l > d) {
shard = shard_prefix(shard, d);
}
if (created_overlays_.count(shard) == 0) {
created_overlays_.insert(shard);
td::actor::send_closure(manager_, &ValidatorManager::subscribe_to_shard, shard);
}
}
}
}
void ShardClient::force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise) {
CHECK(!init_mode_);
CHECK(!started_);
@ -294,10 +284,13 @@ void ShardClient::force_update_shard_client_ex(BlockHandle handle, td::Ref<Maste
masterchain_block_handle_ = std::move(handle);
masterchain_state_ = std::move(state);
promise_ = std::move(promise);
build_shard_overlays();
applied_all_shards();
}
void ShardClient::update_options(td::Ref<ValidatorManagerOptions> opts) {
opts_ = std::move(opts);
}
} // namespace validator
} // namespace ton

View file

@ -42,8 +42,6 @@ class ShardClient : public td::actor::Actor {
td::Promise<td::Unit> promise_;
std::set<ShardIdFull> created_overlays_;
public:
ShardClient(td::Ref<ValidatorManagerOptions> opts, BlockHandle masterchain_block_handle,
td::Ref<MasterchainState> masterchain_state, td::actor::ActorId<ValidatorManager> manager,
@ -64,8 +62,6 @@ class ShardClient : public td::actor::Actor {
return 2;
}
void build_shard_overlays();
void start_up() override;
void start_up_init_mode();
void download_shard_states(BlockIdExt masterchain_block_id, std::vector<BlockIdExt> shards, size_t idx);
@ -90,6 +86,8 @@ class ShardClient : public td::actor::Actor {
void force_update_shard_client(BlockHandle handle, td::Promise<td::Unit> promise);
void force_update_shard_client_ex(BlockHandle handle, td::Ref<MasterchainState> state, td::Promise<td::Unit> promise);
void update_options(td::Ref<ValidatorManagerOptions> opts);
};
} // namespace validator

View file

@ -18,7 +18,6 @@
*/
#include "state-serializer.hpp"
#include "td/utils/Random.h"
#include "adnl/utils.hpp"
#include "ton/ton-io.hpp"
#include "common/delay.h"
#include "td/utils/filesystem.h"
@ -151,6 +150,21 @@ void AsyncStateSerializer::next_iteration() {
CHECK(masterchain_handle_->id() == last_block_id_);
if (attempt_ < max_attempt() && last_key_block_id_.id.seqno < last_block_id_.id.seqno &&
need_serialize(masterchain_handle_)) {
if (!stored_persistent_state_description_) {
LOG(INFO) << "storing persistent state description for " << masterchain_handle_->id().id;
running_ = true;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &AsyncStateSerializer::fail_handler,
R.move_as_error_prefix("failed to get masterchain state: "));
} else {
td::actor::send_closure(SelfId, &AsyncStateSerializer::store_persistent_state_description,
td::Ref<MasterchainState>(R.move_as_ok()));
}
});
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, masterchain_handle_, std::move(P));
return;
}
if (!have_masterchain_state_ && !opts_->get_state_serializer_enabled()) {
LOG(ERROR) << "skipping serializing persistent state for " << masterchain_handle_->id().id.to_str()
<< ": serializer is disabled (by user)";
@ -174,14 +188,10 @@ void AsyncStateSerializer::next_iteration() {
td::Timestamp::in(delay));
return;
}
while (next_idx_ < shards_.size()) {
if (!need_monitor(shards_[next_idx_].shard_full())) {
next_idx_++;
} else {
running_ = true;
request_shard_state(shards_[next_idx_]);
return;
}
if (next_idx_ < shards_.size()) {
running_ = true;
request_shard_state(shards_[next_idx_]);
return;
}
LOG(ERROR) << "finished serializing persistent state for " << masterchain_handle_->id().id.to_str();
}
@ -203,6 +213,7 @@ void AsyncStateSerializer::next_iteration() {
if (masterchain_handle_->inited_next_left()) {
last_block_id_ = masterchain_handle_->one_next(true);
have_masterchain_state_ = false;
stored_persistent_state_description_ = false;
masterchain_handle_ = nullptr;
saved_to_db_ = false;
shards_.clear();
@ -217,6 +228,24 @@ void AsyncStateSerializer::got_top_masterchain_handle(BlockIdExt block_id) {
}
}
void AsyncStateSerializer::store_persistent_state_description(td::Ref<MasterchainState> state) {
stored_persistent_state_description_ = true;
attempt_ = 0;
running_ = false;
PersistentStateDescription desc;
desc.masterchain_id = state->get_block_id();
desc.start_time = state->get_unix_time();
desc.end_time = ValidatorManager::persistent_state_ttl(desc.start_time);
for (const auto &v : state->get_shards()) {
desc.shard_blocks.push_back(v->top_block_id());
}
td::actor::send_closure(manager_, &ValidatorManager::add_persistent_state_description,
td::Ref<PersistentStateDescription>(true, std::move(desc)));
next_iteration();
}
void AsyncStateSerializer::got_masterchain_handle(BlockHandle handle) {
CHECK(!masterchain_handle_);
masterchain_handle_ = std::move(handle);
@ -318,8 +347,10 @@ void AsyncStateSerializer::got_masterchain_state(td::Ref<MasterchainState> state
CHECK(shards_.size() == 0);
auto vec = state->get_shards();
for (auto& v : vec) {
shards_.push_back(v->top_block_id());
for (auto &v : vec) {
if (opts_->need_monitor(v->shard(), state)) {
shards_.push_back(v->top_block_id());
}
}
auto write_data = [shard = state->get_shard(), root = state->root_cell(), cell_db_reader,
@ -447,11 +478,6 @@ void AsyncStateSerializer::auto_disable_serializer(bool disabled) {
}
}
bool AsyncStateSerializer::need_monitor(ShardIdFull shard) {
return opts_->need_monitor(shard);
}
bool AsyncStateSerializer::need_serialize(BlockHandle handle) {
if (handle->id().id.seqno == 0 || !handle->is_key_block()) {
return false;

View file

@ -46,6 +46,7 @@ class AsyncStateSerializer : public td::actor::Actor {
td::uint32 next_idx_ = 0;
BlockHandle masterchain_handle_;
bool stored_persistent_state_description_ = false;
bool have_masterchain_state_ = false;
std::vector<BlockIdExt> shards_;
@ -69,7 +70,6 @@ class AsyncStateSerializer : public td::actor::Actor {
}
bool need_serialize(BlockHandle handle);
bool need_monitor(ShardIdFull shard);
bool have_newer_persistent_state(UnixTime cur_ts);
void alarm() override;
@ -84,6 +84,7 @@ class AsyncStateSerializer : public td::actor::Actor {
void next_iteration();
void got_top_masterchain_handle(BlockIdExt block_id);
void store_persistent_state_description(td::Ref<MasterchainState> state);
void got_masterchain_handle(BlockHandle handle_);
void got_masterchain_state(td::Ref<MasterchainState> state, std::shared_ptr<vm::CellDbReader> cell_db_reader);
void stored_masterchain_state();

View file

@ -26,7 +26,7 @@ namespace validator {
td::Ref<ValidatorManagerOptions> ValidatorManagerOptions::create(
BlockIdExt zero_block_id, BlockIdExt init_block_id,
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard, bool allow_blockchain_init,
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
double sync_blocks_before, double block_ttl, double state_ttl, double max_mempool_num,
double archive_ttl, double key_proof_ttl, bool initial_sync_disabled) {
return td::make_ref<ValidatorManagerOptionsImpl>(zero_block_id, init_block_id, std::move(check_shard),

View file

@ -32,11 +32,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
BlockIdExt init_block_id() const override {
return init_block_id_;
}
bool need_monitor(ShardIdFull shard) const override {
return check_shard_(shard, 0, ShardCheckMode::m_monitor);
}
bool need_validate(ShardIdFull shard, CatchainSeqno cc_seqno) const override {
return check_shard_(shard, cc_seqno, ShardCheckMode::m_validate);
bool need_monitor(ShardIdFull shard, const td::Ref<MasterchainState>& state) const override {
td::uint32 min_split = state->monitor_min_split_depth(shard.workchain);
return check_shard_((td::uint32)shard.pfx_len() <= min_split ? shard : shard_prefix(shard, min_split));
}
bool allow_blockchain_init() const override {
return allow_blockchain_init_;
@ -163,7 +161,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
void set_init_block_id(BlockIdExt block_id) override {
init_block_id_ = block_id;
}
void set_shard_check_function(std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard) override {
void set_shard_check_function(std::function<bool(ShardIdFull)> check_shard) override {
check_shard_ = std::move(check_shard);
}
void set_allow_blockchain_init(bool value) override {
@ -257,11 +255,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
}
ValidatorManagerOptionsImpl(BlockIdExt zero_block_id, BlockIdExt init_block_id,
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard,
bool allow_blockchain_init, double sync_blocks_before,
double block_ttl, double state_ttl, double max_mempool_num,
double archive_ttl, double key_proof_ttl,
bool initial_sync_disabled)
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
double sync_blocks_before, double block_ttl, double state_ttl, double max_mempool_num,
double archive_ttl, double key_proof_ttl, bool initial_sync_disabled)
: zero_block_id_(zero_block_id)
, init_block_id_(init_block_id)
, check_shard_(std::move(check_shard))
@ -278,7 +274,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
private:
BlockIdExt zero_block_id_;
BlockIdExt init_block_id_;
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard_;
std::function<bool(ShardIdFull)> check_shard_;
bool allow_blockchain_init_;
double sync_blocks_before_;
double block_ttl_;

View file

@ -77,8 +77,7 @@ struct ValidatorManagerOptions : public td::CntObject {
virtual BlockIdExt zero_block_id() const = 0;
virtual BlockIdExt init_block_id() const = 0;
virtual bool need_monitor(ShardIdFull shard) const = 0;
virtual bool need_validate(ShardIdFull shard, CatchainSeqno cc_seqno) const = 0;
virtual bool need_monitor(ShardIdFull shard, const td::Ref<MasterchainState>& state) const = 0;
virtual bool allow_blockchain_init() const = 0;
virtual double sync_blocks_before() const = 0;
virtual double block_ttl() const = 0;
@ -118,8 +117,7 @@ struct ValidatorManagerOptions : public td::CntObject {
virtual void set_zero_block_id(BlockIdExt block_id) = 0;
virtual void set_init_block_id(BlockIdExt block_id) = 0;
virtual void set_shard_check_function(
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard) = 0;
virtual void set_shard_check_function(std::function<bool(ShardIdFull)> check_shard) = 0;
virtual void set_allow_blockchain_init(bool value) = 0;
virtual void set_sync_blocks_before(double value) = 0;
virtual void set_block_ttl(double value) = 0;
@ -151,12 +149,11 @@ struct ValidatorManagerOptions : public td::CntObject {
static td::Ref<ValidatorManagerOptions> create(
BlockIdExt zero_block_id, BlockIdExt init_block_id,
std::function<bool(ShardIdFull, CatchainSeqno, ShardCheckMode)> check_shard = [](ShardIdFull, CatchainSeqno,
ShardCheckMode) { return true; },
std::function<bool(ShardIdFull)> check_shard = [](ShardIdFull) { return true; },
bool allow_blockchain_init = false, double sync_blocks_before = 3600, double block_ttl = 86400,
double state_ttl = 86400, double archive_ttl = 86400 * 7, double key_proof_ttl = 86400 * 3650,
double max_mempool_num = 999999,
bool initial_sync_disabled = false);
double max_mempool_num = 999999, bool initial_sync_disabled = false);
};
class ValidatorManagerInterface : public td::actor::Actor {
@ -166,8 +163,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
virtual ~Callback() = default;
virtual void initial_read_complete(BlockHandle top_masterchain_blocks) = 0;
virtual void add_shard(ShardIdFull shard) = 0;
virtual void del_shard(ShardIdFull shard) = 0;
virtual void on_new_masterchain_block(td::Ref<ton::validator::MasterchainState> state,
std::set<ShardIdFull> shards_to_monitor) = 0;
virtual void send_ihr_message(AccountIdPrefixFull dst, td::BufferSlice data) = 0;
virtual void send_ext_message(AccountIdPrefixFull dst, td::BufferSlice data) = 0;
@ -187,8 +184,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
td::Promise<td::BufferSlice> promise) = 0;
virtual void get_next_key_blocks(BlockIdExt block_id, td::Timestamp timeout,
td::Promise<std::vector<BlockIdExt>> promise) = 0;
virtual void download_archive(BlockSeqno masterchain_seqno, std::string tmp_dir, td::Timestamp timeout,
td::Promise<std::string> promise) = 0;
virtual void download_archive(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix, std::string tmp_dir,
td::Timestamp timeout, td::Promise<std::string> promise) = 0;
virtual void new_key_block(BlockHandle handle) = 0;
virtual void send_validator_telemetry(PublicKeyHash key, tl_object_ptr<ton_api::validator_telemetry> telemetry) = 0;
@ -272,7 +269,13 @@ class ValidatorManagerInterface : public td::actor::Actor {
virtual void get_block_by_seqno_from_db(AccountIdPrefixFull account, BlockSeqno seqno,
td::Promise<ConstBlockHandle> promise) = 0;
virtual void get_archive_id(BlockSeqno masterchain_seqno, td::Promise<td::uint64> promise) = 0;
virtual void wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void wait_block_state_short(BlockIdExt block_id, td::uint32 priority, td::Timestamp timeout,
td::Promise<td::Ref<ShardState>> promise) = 0;
virtual void get_archive_id(BlockSeqno masterchain_seqno, ShardIdFull shard_prefix,
td::Promise<td::uint64> promise) = 0;
virtual void get_archive_slice(td::uint64 archive_id, td::uint64 offset, td::uint32 limit,
td::Promise<td::BufferSlice> promise) = 0;