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

updated tonlib, fixed bugs

updated tonlib
fixed bugs in func
validator: partial support for hardforks
liteserver: support for waitMasterchainBlock prefix
transactions: support for gas flat rate
This commit is contained in:
ton 2019-10-03 17:04:52 +04:00
parent 841d5ebac2
commit 7ea00ebfcf
89 changed files with 1922 additions and 608 deletions

View file

@ -473,6 +473,21 @@ struct BlockHandleImpl : public BlockHandleInterface {
}
}
void unsafe_clear_applied() override {
if (is_applied()) {
lock();
flags_ &= ~Flags::dbf_applied;
unlock();
}
}
void unsafe_clear_next() override {
if (inited_next_left() || inited_next_right()) {
lock();
flags_ &= ~(Flags::dbf_inited_next_left | Flags::dbf_inited_next_right);
unlock();
}
}
td::BufferSlice serialize() const override;
BlockHandleImpl(BlockIdExt id)
: id_(id), flags_(id_.is_masterchain() ? static_cast<td::uint32>(dbf_masterchain) : 0) {

View file

@ -229,6 +229,73 @@ tl_object_ptr<ton_api::db_blockdb_lru> BlockDb::DbEntry::release() {
return create_tl_object<ton_api::db_blockdb_lru>(create_tl_block_id(block_id), prev, next);
}
void BlockDb::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {
std::map<ShardIdFull, BlockSeqno> max_seqno;
max_seqno.emplace(ShardIdFull{masterchainId}, state->get_seqno() + 1);
auto shards = state->get_shards();
auto it = KeyHash::zero();
kv_->begin_transaction().ensure();
while (true) {
auto R = get_block_lru(it);
R.ensure();
auto v = R.move_as_ok();
it = v.next;
R = get_block_lru(it);
R.ensure();
v = R.move_as_ok();
if (v.is_empty()) {
break;
}
auto s = v.block_id.shard_full();
if (!max_seqno.count(s)) {
bool found = false;
for (auto &shard : shards) {
if (shard_intersects(shard->shard(), s)) {
found = true;
max_seqno.emplace(s, shard->top_block_id().seqno() + 1);
break;
}
}
if (!found) {
max_seqno.emplace(s, 0);
}
}
bool to_delete = v.block_id.seqno() >= max_seqno[s];
if (to_delete) {
auto key_hash = get_block_value_key(v.block_id);
auto B = get_block_value(key_hash);
B.ensure();
auto handleR = create_block_handle(B.move_as_ok());
handleR.ensure();
auto handle = handleR.move_as_ok();
handle->unsafe_clear_applied();
handle->unsafe_clear_next();
if (handle->need_flush()) {
set_block_value(key_hash, handle->serialize());
}
} else if (v.block_id.seqno() + 1 == max_seqno[s]) {
auto key_hash = get_block_value_key(v.block_id);
auto B = get_block_value(key_hash);
B.ensure();
auto handleR = create_block_handle(B.move_as_ok());
handleR.ensure();
auto handle = handleR.move_as_ok();
handle->unsafe_clear_next();
if (handle->need_flush()) {
set_block_value(key_hash, handle->serialize());
}
}
}
kv_->commit_transaction().ensure();
}
} // namespace validator
} // namespace ton

View file

@ -41,6 +41,8 @@ class BlockDb : public td::actor::Actor {
void gc();
void skip_gc();
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise);
BlockDb(td::actor::ActorId<RootDb> root_db, std::string db_path);
private:

View file

@ -138,7 +138,7 @@ void FileDb::load_file(RefId ref_id, td::Promise<td::BufferSlice> promise) {
}
});
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), 0, -1, std::move(P)).release();
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), 0, -1, 0, std::move(P)).release();
}
void FileDb::load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size, td::Promise<td::BufferSlice> promise) {
@ -159,7 +159,7 @@ void FileDb::load_file_slice(RefId ref_id, td::int64 offset, td::int64 max_size,
}
});
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), offset, max_size, std::move(P))
td::actor::create_actor<db::ReadFile>("readfile", get_file_name(ref_id, false), offset, max_size, 0, std::move(P))
.release();
}

View file

@ -81,25 +81,32 @@ class WriteFile : public td::actor::Actor {
class ReadFile : public td::actor::Actor {
public:
enum Flags : td::uint32 { f_disable_log = 1 };
void start_up() override {
auto S = td::read_file(file_name_, max_length_, offset_);
if (S.is_ok()) {
promise_.set_result(S.move_as_ok());
} else {
// TODO check error code
LOG(ERROR) << "missing file " << file_name_;
if (flags_ & Flags::f_disable_log) {
LOG(DEBUG) << "missing file " << file_name_;
} else {
LOG(ERROR) << "missing file " << file_name_;
}
promise_.set_error(td::Status::Error(ErrorCode::notready, "file does not exist"));
}
stop();
}
ReadFile(std::string file_name, td::int64 offset, td::int64 max_length, td::Promise<td::BufferSlice> promise)
: file_name_(file_name), offset_(offset), max_length_(max_length), promise_(std::move(promise)) {
ReadFile(std::string file_name, td::int64 offset, td::int64 max_length, td::uint32 flags,
td::Promise<td::BufferSlice> promise)
: file_name_(file_name), offset_(offset), max_length_(max_length), flags_(flags), promise_(std::move(promise)) {
}
private:
std::string file_name_;
td::int64 offset_;
td::int64 max_length_;
td::uint32 flags_;
td::Promise<td::BufferSlice> promise_;
};

View file

@ -216,6 +216,95 @@ void LtDb::start_up() {
kv_ = std::make_shared<td::RocksDb>(td::RocksDb::open(db_path_).move_as_ok());
}
void LtDb::truncate_workchain(ShardIdFull shard, td::Ref<MasterchainState> state) {
auto key = get_desc_key(shard);
std::string value;
auto R = kv_->get(key, value);
R.ensure();
CHECK(R.move_as_ok() == td::KeyValue::GetStatus::Ok);
auto F = fetch_tl_object<ton_api::db_lt_desc_value>(td::BufferSlice{value}, true);
F.ensure();
auto f = F.move_as_ok();
auto shards = state->get_shards();
BlockSeqno seqno = 0;
if (shard.is_masterchain()) {
seqno = state->get_seqno();
} else {
for (auto s : shards) {
if (shard_intersects(s->shard(), shard)) {
seqno = s->top_block_id().seqno();
break;
}
}
}
while (f->last_idx_ > f->first_idx_) {
auto db_key = get_el_key(shard, f->last_idx_ - 1);
R = kv_->get(db_key, value);
R.ensure();
CHECK(R.move_as_ok() == td::KeyValue::GetStatus::Ok);
auto E = fetch_tl_object<ton_api::db_lt_el_value>(td::BufferSlice{value}, true);
E.ensure();
auto e = E.move_as_ok();
bool to_delete = static_cast<td::uint32>(e->id_->seqno_) > seqno;
if (!to_delete) {
break;
} else {
f->last_idx_--;
kv_->erase(db_key).ensure();
}
}
if (f->first_idx_ == f->last_idx_) {
f->last_ts_ = 0;
f->last_lt_ = 0;
f->last_seqno_ = 0;
}
kv_->set(key, serialize_tl_object(f, true)).ensure();
}
void LtDb::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {
auto status_key = create_serialize_tl_object<ton_api::db_lt_status_key>();
td::Result<td::KeyValue::GetStatus> R;
td::uint32 total_shards = 0;
{
std::string value;
R = kv_->get(status_key.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_value(td::Unit());
return;
}
auto F = fetch_tl_object<ton_api::db_lt_status_value>(value, true);
F.ensure();
auto f = F.move_as_ok();
total_shards = f->total_shards_;
if (total_shards == 0) {
promise.set_value(td::Unit());
return;
}
}
kv_->begin_transaction().ensure();
for (td::uint32 idx = 0; idx < total_shards; idx++) {
auto shard_key = create_serialize_tl_object<ton_api::db_lt_shard_key>(idx);
std::string value;
R = kv_->get(shard_key.as_slice(), value);
R.ensure();
CHECK(R.move_as_ok() == td::KeyValue::GetStatus::Ok);
auto F = fetch_tl_object<ton_api::db_lt_shard_value>(value, true);
F.ensure();
auto f = F.move_as_ok();
truncate_workchain(ShardIdFull{f->workchain_, static_cast<td::uint64>(f->shard_)}, state);
}
kv_->commit_transaction().ensure();
promise.set_value(td::Unit());
}
} // namespace validator
} // namespace ton

View file

@ -20,6 +20,7 @@
#include "td/actor/actor.h"
#include "td/db/KeyValueAsync.h"
#include "validator/interfaces/db.h"
#include "ton/ton-types.h"
@ -42,6 +43,9 @@ class LtDb : public td::actor::Actor {
void get_block_by_unix_time(AccountIdPrefixFull account_id, UnixTime ts, td::Promise<BlockIdExt> promise);
void get_block_by_seqno(AccountIdPrefixFull account_id, BlockSeqno seqno, td::Promise<BlockIdExt> promise);
void truncate_workchain(ShardIdFull shard, td::Ref<MasterchainState> state);
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise);
void start_up() override;
LtDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(std::move(db_path)) {

View file

@ -25,6 +25,7 @@
#include "td/utils/overloaded.h"
#include "common/checksum.h"
#include "validator/stats-merger.h"
#include "td/actor/MultiPromise.h"
namespace ton {
@ -413,6 +414,14 @@ void RootDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promis
td::actor::send_closure(state_db_, &StateDb::get_async_serializer_state, std::move(promise));
}
void RootDb::update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise) {
td::actor::send_closure(state_db_, &StateDb::update_hardforks, std::move(blocks), std::move(promise));
}
void RootDb::get_hardforks(td::Promise<std::vector<BlockIdExt>> promise) {
td::actor::send_closure(state_db_, &StateDb::get_hardforks, std::move(promise));
}
void RootDb::start_up() {
cell_db_ = td::actor::create_actor<CellDb>("celldb", actor_id(this), root_path_ + "/celldb/");
block_db_ = td::actor::create_actor<BlockDb>("blockdb", actor_id(this), root_path_ + "/blockdb/");
@ -481,6 +490,15 @@ void RootDb::prepare_stats(td::Promise<std::vector<std::pair<std::string, std::s
td::actor::send_closure(archive_db_, &FileDb::prepare_stats, merger.make_promise("archivedb."));
}
void RootDb::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {
td::MultiPromise mp;
auto ig = mp.init_guard();
ig.add_promise(std::move(promise));
td::actor::send_closure(lt_db_, &LtDb::truncate, state, ig.get_promise());
td::actor::send_closure(block_db_, &BlockDb::truncate, state, ig.get_promise());
}
} // namespace validator
} // namespace ton

View file

@ -104,6 +104,9 @@ class RootDb : public Db {
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise) override;
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise) override;
void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise) override;
void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise) override;
void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) override;
void allow_state_gc(BlockIdExt block_id, td::Promise<bool> promise);
@ -112,6 +115,8 @@ class RootDb : public Db {
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override;
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) override;
private:
td::actor::ActorId<ValidatorManager> validator_manager_;

View file

@ -179,6 +179,44 @@ void StateDb::get_async_serializer_state(td::Promise<AsyncSerializerState> promi
static_cast<UnixTime>(obj->last_ts_)});
}
void StateDb::update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_hardforks>();
std::vector<tl_object_ptr<ton_api::tonNode_blockIdExt>> vec;
for (auto &e : blocks) {
vec.push_back(create_tl_block_id(e));
}
kv_->begin_transaction().ensure();
kv_->set(key.as_slice(), create_serialize_tl_object<ton_api::db_state_hardforks>(std::move(vec))).ensure();
kv_->commit_transaction();
promise.set_value(td::Unit());
}
void StateDb::get_hardforks(td::Promise<std::vector<BlockIdExt>> promise) {
auto key = create_hash_tl_object<ton_api::db_state_key_hardforks>();
std::string value;
auto R = kv_->get(key.as_slice(), value);
R.ensure();
if (R.move_as_ok() == td::KeyValue::GetStatus::NotFound) {
promise.set_value(std::vector<BlockIdExt>{});
return;
}
auto F = fetch_tl_object<ton_api::db_state_hardforks>(value, true);
F.ensure();
auto f = F.move_as_ok();
std::vector<BlockIdExt> vec;
for (auto &e : f->blocks_) {
vec.push_back(create_block_id(e));
}
promise.set_value(std::move(vec));
}
StateDb::StateDb(td::actor::ActorId<RootDb> root_db, std::string db_path) : root_db_(root_db), db_path_(db_path) {
}

View file

@ -47,6 +47,9 @@ class StateDb : public td::actor::Actor {
void update_async_serializer_state(AsyncSerializerState state, td::Promise<td::Unit> promise);
void get_async_serializer_state(td::Promise<AsyncSerializerState> promise);
void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise);
void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise);
StateDb(td::actor::ActorId<RootDb> root_db, std::string path);
void start_up() override;

View file

@ -25,7 +25,9 @@ namespace validator {
void StaticFilesDb::load_file(FileHash file_hash, td::Promise<td::BufferSlice> promise) {
auto path = path_ + "/" + file_hash.to_hex();
td::actor::create_actor<db::ReadFile>("read file", path, 0, -1, std::move(promise)).release();
td::actor::create_actor<db::ReadFile>("read file", path, 0, -1, db::ReadFile::Flags::f_disable_log,
std::move(promise))
.release();
}
} // namespace validator

View file

@ -56,6 +56,20 @@ void WaitBlockData::start_up() {
alarm_timestamp() = timeout_;
CHECK(handle_);
if (!handle_->id().is_masterchain()) {
start();
} else {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<bool> R) {
R.ensure();
auto value = R.move_as_ok();
td::actor::send_closure(SelfId, &WaitBlockData::set_is_hardfork, value);
});
td::actor::send_closure(manager_, &ValidatorManager::check_is_hardfork, handle_->id(), std::move(P));
}
}
void WaitBlockData::set_is_hardfork(bool value) {
is_hardfork_ = value;
start();
}
@ -76,6 +90,18 @@ void WaitBlockData::start() {
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
} else if (try_read_static_file_.is_in_past() && (is_hardfork_ || !handle_->id().is_masterchain())) {
try_read_static_file_ = td::Timestamp::in(30.0);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::BufferSlice> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &WaitBlockData::start);
} else {
td::actor::send_closure(SelfId, &WaitBlockData::got_static_file, R.move_as_ok());
}
});
td::actor::send_closure(manager_, &ValidatorManager::try_get_static_file, handle_->id().file_hash, std::move(P));
} else {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ReceivedBlock> R) {
if (R.is_error()) {
@ -149,6 +175,29 @@ void WaitBlockData::force_read_from_db() {
td::actor::send_closure(manager_, &ValidatorManager::get_block_data_from_db, handle_, std::move(P));
}
void WaitBlockData::got_static_file(td::BufferSlice data) {
CHECK(td::sha256_bits256(data.as_slice()) == handle_->id().file_hash);
auto R = create_block(handle_->id(), std::move(data));
if (R.is_error()) {
LOG(ERROR) << "bad static file block: " << R.move_as_error();
start();
return;
}
data_ = R.move_as_ok();
CHECK(is_hardfork_ || !handle_->id().is_masterchain());
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &WaitBlockData::abort_query, R.move_as_error_prefix("bad static file block: "));
} else {
td::actor::send_closure(SelfId, &WaitBlockData::finish_query);
}
});
run_hardfork_accept_block_query(handle_->id(), data_, manager_, std::move(P));
}
} // namespace validator
} // namespace ton

View file

@ -51,12 +51,14 @@ class WaitBlockData : public td::actor::Actor {
void force_read_from_db();
void start_up() override;
void got_block_handle(BlockHandle handle);
void set_is_hardfork(bool value);
void start();
void got_block_data_from_db(td::Ref<BlockData> data);
void got_block_data_from_net(ReceivedBlock data);
void failed_to_get_block_data_from_net(td::Status reason);
void got_static_file(td::BufferSlice data);
private:
BlockHandle handle_;
@ -69,6 +71,8 @@ class WaitBlockData : public td::actor::Actor {
td::Ref<BlockData> data_;
bool reading_from_db_ = false;
bool is_hardfork_ = false;
td::Timestamp try_read_static_file_ = td::Timestamp::now();
//td::PerfWarningTimer perf_timer_{"waitdata", 1.0};
};

View file

@ -52,6 +52,8 @@ void run_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<
void run_fake_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
td::Ref<ValidatorSet> validator_set, td::actor::ActorId<ValidatorManager> manager,
td::Promise<td::Unit> promise);
void run_hardfork_accept_block_query(BlockIdExt id, td::Ref<BlockData> data,
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise);
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<td::Unit> promise);
void run_check_proof_query(BlockIdExt id, td::Ref<Proof> proof, td::actor::ActorId<ValidatorManager> manager,

View file

@ -1466,26 +1466,10 @@ bool Collator::fetch_config_params() {
if (cell.is_null()) {
return fatal_error("cannot fetch current gas prices and limits from masterchain configuration");
}
auto f = [self = this](const auto& r, td::uint64 spec_limit) {
self->compute_phase_cfg_.gas_limit = r.gas_limit;
self->compute_phase_cfg_.special_gas_limit = spec_limit;
self->compute_phase_cfg_.gas_credit = r.gas_credit;
self->compute_phase_cfg_.gas_price = r.gas_price;
self->storage_phase_cfg_.freeze_due_limit = td::RefInt256{true, r.freeze_due_limit};
self->storage_phase_cfg_.delete_due_limit = td::RefInt256{true, r.delete_due_limit};
};
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
if (tlb::unpack_cell(cell, rec)) {
f(rec, rec.special_gas_limit);
} else {
block::gen::GasLimitsPrices::Record_gas_prices rec0;
if (tlb::unpack_cell(std::move(cell), rec0)) {
f(rec0, rec0.gas_limit);
} else {
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
}
if (!compute_phase_cfg_.parse_GasLimitsPrices(std::move(cell), storage_phase_cfg_.freeze_due_limit,
storage_phase_cfg_.delete_due_limit)) {
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
}
compute_phase_cfg_.compute_threshold();
compute_phase_cfg_.block_rand_seed = rand_seed_;
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256);
compute_phase_cfg_.global_config = config_->get_root_cell();

View file

@ -33,6 +33,7 @@
#include "top-shard-descr.hpp"
#include "ton/ton-io.hpp"
#include "liteserver.hpp"
#include "validator/fabric.h"
namespace ton {
@ -131,6 +132,11 @@ void run_fake_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::ve
.release();
}
void run_hardfork_accept_block_query(BlockIdExt id, td::Ref<BlockData> data,
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise) {
promise.set_error(td::Status::Error(ErrorCode::error, "not implemented"));
}
void run_apply_block_query(BlockIdExt id, td::Ref<BlockData> block, td::actor::ActorId<ValidatorManager> manager,
td::Timestamp timeout, td::Promise<td::Unit> promise) {
td::actor::create_actor<ApplyBlock>(PSTRING() << "apply " << id, id, std::move(block), manager, timeout,

View file

@ -192,7 +192,7 @@ void LiteQuery::perform_getMasterchainInfo(int mode) {
}
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
[ Self = actor_id(this), mode ](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) {
[Self = actor_id(this), mode](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
@ -230,7 +230,7 @@ void LiteQuery::perform_getBlock(BlockIdExt blkid) {
return;
}
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
[ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::BlockData>> res) {
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
@ -256,7 +256,7 @@ void LiteQuery::perform_getBlockHeader(BlockIdExt blkid, int mode) {
return;
}
td::actor::send_closure_later(manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
[ Self = actor_id(this), blkid, mode ](td::Result<Ref<ton::validator::BlockData>> res) {
[Self = actor_id(this), blkid, mode](td::Result<Ref<ton::validator::BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
@ -371,7 +371,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
}
if (blkid.id.seqno) {
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
[ Self = actor_id(this), blkid ](td::Result<Ref<ton::validator::ShardState>> res) {
[Self = actor_id(this), blkid](td::Result<Ref<ton::validator::ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
@ -381,7 +381,7 @@ void LiteQuery::perform_getState(BlockIdExt blkid) {
});
} else {
td::actor::send_closure_later(manager_, &ValidatorManager::get_zero_state, blkid,
[ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
@ -440,7 +440,7 @@ bool LiteQuery::request_mc_block_data(BlockIdExt blkid) {
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
@ -466,7 +466,7 @@ bool LiteQuery::request_mc_proof(BlockIdExt blkid, int mode) {
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_proof_from_db_short, blkid,
[ Self = actor_id(this), blkid, mode ](td::Result<Ref<Proof>> res) {
[Self = actor_id(this), blkid, mode](td::Result<Ref<Proof>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load proof for "s + blkid.to_str() + " : "));
@ -488,7 +488,7 @@ bool LiteQuery::request_mc_block_state(BlockIdExt blkid) {
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
@ -519,7 +519,7 @@ bool LiteQuery::request_block_state(BlockIdExt blkid) {
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_shard_state_from_db_short, blkid,
[ Self = actor_id(this), blkid ](td::Result<Ref<ShardState>> res) {
[Self = actor_id(this), blkid](td::Result<Ref<ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load state for "s + blkid.to_str() + " : "));
@ -541,7 +541,7 @@ bool LiteQuery::request_block_data(BlockIdExt blkid) {
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_data_from_db_short, blkid,
[ Self = actor_id(this), blkid ](td::Result<Ref<BlockData>> res) {
[Self = actor_id(this), blkid](td::Result<Ref<BlockData>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load block "s + blkid.to_str() + " : "));
@ -563,7 +563,7 @@ bool LiteQuery::request_proof_link(BlockIdExt blkid) {
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_proof_link_from_db_short, blkid,
[ Self = actor_id(this), blkid ](td::Result<Ref<ProofLink>> res) {
[Self = actor_id(this), blkid](td::Result<Ref<ProofLink>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load proof link for "s + blkid.to_str() + " : "));
@ -588,7 +588,7 @@ bool LiteQuery::request_zero_state(BlockIdExt blkid) {
++pending_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_zero_state, blkid,
[ Self = actor_id(this), blkid ](td::Result<td::BufferSlice> res) {
[Self = actor_id(this), blkid](td::Result<td::BufferSlice> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot load zerostate of "s + blkid.to_str() + " : "));
@ -632,7 +632,7 @@ void LiteQuery::perform_getAccountState(BlockIdExt blkid, WorkchainId workchain,
LOG(INFO) << "sending a get_top_masterchain_state_block query to manager";
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
[Self = actor_id(this)](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res)->void {
[Self = actor_id(this)](td::Result<std::pair<Ref<ton::validator::MasterchainState>, BlockIdExt>> res) -> void {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
@ -1067,7 +1067,7 @@ void LiteQuery::continue_getTransactions(unsigned remaining, bool exact) {
<< " " << trans_lt_;
td::actor::send_closure_later(
manager_, &ValidatorManager::get_block_by_lt_from_db, ton::extract_addr_prefix(acc_workchain_, acc_addr_),
trans_lt_, [ Self = actor_id(this), remaining, manager = manager_ ](td::Result<BlockIdExt> res) {
trans_lt_, [Self = actor_id(this), remaining, manager = manager_](td::Result<BlockIdExt> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_getTransactions, res.move_as_error(), ton::BlockIdExt{});
} else {
@ -1141,7 +1141,7 @@ void LiteQuery::perform_getShardInfo(BlockIdExt blkid, ShardIdFull shard, bool e
void LiteQuery::perform_getConfigParams(BlockIdExt blkid, int mode, std::vector<int> param_list) {
LOG(INFO) << "started a getConfigParams(" << blkid.to_str() << ", " << mode << ", <list of " << param_list.size()
<< " parameters>) liteserver query";
set_continuation([ this, mode, param_list = std::move(param_list) ]() mutable {
set_continuation([this, mode, param_list = std::move(param_list)]() mutable {
continue_getConfigParams(mode, std::move(param_list));
});
request_mc_block_data_state(blkid);
@ -1294,7 +1294,7 @@ void LiteQuery::perform_lookupBlock(BlockId blkid, int mode, LogicalTime lt, Uni
LOG(INFO) << "performing a lookupBlock(" << blkid.to_str() << ", " << mode << ", " << lt << ", " << utime
<< ") query";
auto P = td::PromiseCreator::lambda(
[ Self = actor_id(this), manager = manager_, mode = (mode >> 4) ](td::Result<BlockIdExt> res) {
[Self = actor_id(this), manager = manager_, mode = (mode >> 4)](td::Result<BlockIdExt> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
@ -1445,10 +1445,21 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
fatal_error("destination block "s + to.to_str() + " is not a valid masterchain block id");
return;
}
if (!(mode & 1)) {
if (mode & 1) {
base_blk_id_ = (from.seqno() > to.seqno()) ? from : to;
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, base_blk_id_,
[Self = actor_id(this), from, to, mode](td::Result<Ref<ShardState>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, to,
mode, Ref<MasterchainStateQ>(res.move_as_ok()));
}
});
} else if (mode & 2) {
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
[ Self = actor_id(this), from, mode ](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res)->void {
[Self = actor_id(this), from, mode](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
@ -1458,14 +1469,13 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
}
});
} else {
base_blk_id_ = (from.seqno() > to.seqno()) ? from : to;
td::actor::send_closure_later(manager_, &ValidatorManager::get_shard_state_from_db_short, base_blk_id_,
[ Self = actor_id(this), from, to, mode ](td::Result<Ref<ShardState>> res) {
td::actor::send_closure_later(manager_, &ton::validator::ValidatorManager::get_shard_client_state, false,
[Self = actor_id(this), from, mode](td::Result<BlockIdExt> res) {
if (res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query, res.move_as_error());
} else {
td::actor::send_closure_later(Self, &LiteQuery::continue_getBlockProof, from, to,
mode, Ref<MasterchainStateQ>(res.move_as_ok()));
td::actor::send_closure_later(Self, &LiteQuery::perform_getBlockProof, from,
res.move_as_ok(), mode | 1);
}
});
}

View file

@ -734,26 +734,10 @@ bool ValidateQuery::fetch_config_params() {
if (cell.is_null()) {
return fatal_error("cannot fetch current gas prices and limits from masterchain configuration");
}
auto f = [self = this](const auto& r, td::uint64 spec_limit) {
self->compute_phase_cfg_.gas_limit = r.gas_limit;
self->compute_phase_cfg_.special_gas_limit = spec_limit;
self->compute_phase_cfg_.gas_credit = r.gas_credit;
self->compute_phase_cfg_.gas_price = r.gas_price;
self->storage_phase_cfg_.freeze_due_limit = td::RefInt256{true, r.freeze_due_limit};
self->storage_phase_cfg_.delete_due_limit = td::RefInt256{true, r.delete_due_limit};
};
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
if (tlb::unpack_cell(cell, rec)) {
f(rec, rec.special_gas_limit);
} else {
block::gen::GasLimitsPrices::Record_gas_prices rec0;
if (tlb::unpack_cell(std::move(cell), rec0)) {
f(rec0, rec0.gas_limit);
} else {
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
}
if (!compute_phase_cfg_.parse_GasLimitsPrices(std::move(cell), storage_phase_cfg_.freeze_due_limit,
storage_phase_cfg_.delete_due_limit)) {
return fatal_error("cannot unpack current gas prices and limits from masterchain configuration");
}
compute_phase_cfg_.compute_threshold();
compute_phase_cfg_.block_rand_seed = rand_seed_;
compute_phase_cfg_.libraries = std::make_unique<vm::Dictionary>(config_->get_libraries_root(), 256);
compute_phase_cfg_.global_config = config_->get_root_cell();
@ -5227,7 +5211,7 @@ bool ValidateQuery::check_block_create_stats() {
auto key = td::Bits256::zero();
auto old_val = ps_.block_create_stats_->lookup(key);
auto new_val = ns_.block_create_stats_->lookup(key);
if (new_val.is_null()) {
if (new_val.is_null() && (!created_by_.is_zero() || block_create_total_)) {
return reject_query(
"new masterchain state does not contain a BlockCreator entry with zero key with total statistics");
}

View file

@ -93,6 +93,9 @@ struct BlockHandleInterface {
virtual void set_archived() = 0;
virtual void set_applied() = 0;
virtual void unsafe_clear_applied() = 0;
virtual void unsafe_clear_next() = 0;
virtual td::BufferSlice serialize() const = 0;
virtual ~BlockHandleInterface() = default;

View file

@ -92,9 +92,14 @@ class Db : public td::actor::Actor {
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;
virtual void update_hardforks(std::vector<BlockIdExt> blocks, td::Promise<td::Unit> promise) = 0;
virtual void get_hardforks(td::Promise<std::vector<BlockIdExt>> promise) = 0;
virtual void archive(BlockIdExt block_id, td::Promise<td::Unit> promise) = 0;
virtual void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) = 0;
virtual void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) = 0;
};
} // namespace validator

View file

@ -128,7 +128,7 @@ class ValidatorManager : public ValidatorManagerInterface {
virtual void send_block_broadcast(BlockBroadcast broadcast) = 0;
virtual void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) = 0;
virtual void get_shard_client_state(td::Promise<BlockIdExt> 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;
@ -153,6 +153,12 @@ class ValidatorManager : public ValidatorManagerInterface {
virtual void update_last_known_key_block(BlockHandle handle, bool send_request) = 0;
virtual void update_gc_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
virtual void update_shard_client_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
virtual void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) = 0;
virtual void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) = 0;
static bool is_persistent_state(UnixTime ts, UnixTime prev_ts) {
return ts / 1024 != prev_ts / 1024;
}

View file

@ -897,7 +897,7 @@ void ValidatorManagerImpl::update_shard_client_state(BlockIdExt masterchain_bloc
td::actor::send_closure(db_, &Db::update_shard_client_state, masterchain_block_id, std::move(promise));
}
void ValidatorManagerImpl::get_shard_client_state(td::Promise<BlockIdExt> promise) {
void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) {
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
}

View file

@ -241,7 +241,7 @@ class ValidatorManagerImpl : public ValidatorManager {
}
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
void get_shard_client_state(td::Promise<BlockIdExt> promise) override;
void get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) override;
void subscribe_to_shard(ShardIdFull shard) override {
}
@ -329,11 +329,20 @@ class ValidatorManagerImpl : public ValidatorManager {
}
void update_last_known_key_block(BlockHandle handle, bool send_request) override {
}
void update_shard_client_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override {
}
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override {
UNREACHABLE();
}
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) override {
UNREACHABLE();
}
void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) override {
UNREACHABLE();
}
private:
PublicKeyHash local_id_;

View file

@ -25,6 +25,7 @@
#include "adnl/utils.hpp"
#include "validator/downloaders/download-state.hpp"
#include "common/delay.h"
#include "td/actor/MultiPromise.h"
namespace ton {
@ -33,7 +34,16 @@ namespace validator {
void ValidatorManagerMasterchainReiniter::start_up() {
CHECK(block_id_.is_masterchain());
CHECK(block_id_.id.shard == shardIdAll);
CHECK(block_id_.seqno() >= opts_->get_last_fork_masterchain_seqno());
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::written_hardforks);
});
td::actor::send_closure(db_, &Db::update_hardforks, opts_->get_hardforks(), std::move(P));
}
void ValidatorManagerMasterchainReiniter::written_hardforks() {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainReiniter::got_masterchain_handle, R.move_as_ok());
@ -268,7 +278,7 @@ void ValidatorManagerMasterchainStarter::start_up() {
}
void ValidatorManagerMasterchainStarter::failed_to_get_init_block_id() {
td::actor::create_actor<ValidatorManagerMasterchainReiniter>("reiniter", opts_, manager_, std::move(promise_))
td::actor::create_actor<ValidatorManagerMasterchainReiniter>("reiniter", opts_, manager_, db_, std::move(promise_))
.release();
stop();
}
@ -351,7 +361,7 @@ void ValidatorManagerMasterchainStarter::got_gc_block_state(td::Ref<MasterchainS
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_shard_block_id, R.move_as_ok());
});
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, std::move(P));
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, true, std::move(P));
return;
}
@ -375,15 +385,169 @@ void ValidatorManagerMasterchainStarter::got_key_block_handle(BlockHandle handle
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_shard_block_id, R.move_as_ok());
});
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, std::move(P));
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, true, std::move(P));
}
void ValidatorManagerMasterchainStarter::got_shard_block_id(BlockIdExt block_id) {
client_ = td::actor::create_actor<ShardClient>("shardclient", opts_, manager_);
client_block_id_ = block_id;
finish();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::vector<BlockIdExt>> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_hardforks, R.move_as_ok());
});
td::actor::send_closure(db_, &Db::get_hardforks, std::move(P));
}
void ValidatorManagerMasterchainStarter::got_hardforks(std::vector<BlockIdExt> vec) {
auto h = opts_->get_hardforks();
if (h.size() < vec.size()) {
LOG(FATAL) << "cannot start: number of hardforks decreased";
return;
}
if (h.size() == vec.size()) {
if (h.size() > 0) {
if (*h.rbegin() != *vec.rbegin()) {
LOG(FATAL) << "cannot start: hardforks list changed";
return;
}
}
finish();
return;
}
if (h.size() > vec.size() + 1) {
LOG(FATAL) << "cannot start: number of hardforks increase is too big";
return;
}
auto b = *h.rbegin();
if (b.seqno() > handle_->id().seqno()) {
truncated();
return;
}
if (b.seqno() <= gc_handle_->id().seqno()) {
LOG(FATAL) << "cannot start: new hardfork is on too old block (already gc'd)";
return;
}
BlockIdExt id;
if (state_->get_old_mc_block_id(b.seqno() - 1, id)) {
got_truncate_block_id(id);
return;
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockIdExt> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_truncate_block_id, R.move_as_ok());
});
td::actor::send_closure(db_, &Db::get_block_by_seqno, AccountIdPrefixFull{masterchainId, 0}, b.seqno() - 1,
std::move(P));
}
void ValidatorManagerMasterchainStarter::got_truncate_block_id(BlockIdExt block_id) {
block_id_ = block_id;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<BlockHandle> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_truncate_block_handle, R.move_as_ok());
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, block_id_, false, std::move(P));
}
void ValidatorManagerMasterchainStarter::got_truncate_block_handle(BlockHandle handle) {
handle_ = std::move(handle);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_truncate_state,
td::Ref<MasterchainState>{R.move_as_ok()});
});
td::actor::send_closure(db_, &Db::get_block_state, handle_, std::move(P));
}
void ValidatorManagerMasterchainStarter::got_truncate_state(td::Ref<MasterchainState> state) {
state_ = std::move(state);
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::truncated_db);
});
td::actor::send_closure(manager_, &ValidatorManager::truncate, state_, std::move(P));
}
void ValidatorManagerMasterchainStarter::truncated_db() {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::truncated);
});
auto key = state_->last_key_block_id();
td::MultiPromise mp;
auto ig = mp.init_guard();
ig.add_promise(std::move(P));
td::actor::send_closure(db_, &Db::update_init_masterchain_block, block_id_, ig.get_promise());
if (client_block_id_.seqno() > block_id_.seqno()) {
client_block_id_ = block_id_;
td::actor::send_closure(db_, &Db::update_shard_client_state, client_block_id_, ig.get_promise());
}
if (last_key_block_handle_->id().seqno() > key.seqno()) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this),
promise = ig.get_promise()](td::Result<BlockHandle> R) mutable {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::got_prev_key_block_handle, R.move_as_ok());
promise.set_value(td::Unit());
});
td::actor::send_closure(manager_, &ValidatorManager::get_block_handle, key, false, std::move(P));
}
{
auto P = td::PromiseCreator::lambda(
[b = block_id_, key, db = db_, promise = ig.get_promise()](td::Result<AsyncSerializerState> R) mutable {
if (R.is_error()) {
promise.set_value(td::Unit());
return;
}
auto s = R.move_as_ok();
if (s.last_block_id.seqno() <= b.seqno()) {
promise.set_value(td::Unit());
return;
}
s.last_block_id = b;
if (s.last_written_block_id.seqno() > b.seqno()) {
s.last_written_block_id = key;
s.last_written_block_ts = 0; // may lead to extra state snapshot on disk. Does not seem like a problem
}
td::actor::send_closure(db, &Db::update_async_serializer_state, s, std::move(promise));
});
td::actor::send_closure(db_, &Db::get_async_serializer_state, std::move(P));
}
}
void ValidatorManagerMasterchainStarter::got_prev_key_block_handle(BlockHandle handle) {
last_key_block_handle_ = std::move(handle);
}
void ValidatorManagerMasterchainStarter::truncated() {
handle_->set_next(*opts_->get_hardforks().rbegin());
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::written_next);
});
handle_->flush(manager_, handle_, std::move(P));
}
void ValidatorManagerMasterchainStarter::written_next() {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ValidatorManagerMasterchainStarter::finish);
});
td::actor::send_closure(db_, &Db::update_hardforks, opts_->get_hardforks(), std::move(P));
}
void ValidatorManagerMasterchainStarter::finish() {
client_ = td::actor::create_actor<ShardClient>("shardclient", opts_, manager_);
promise_.set_value(
ValidatorManagerInitResult{handle_, state_, std::move(client_), gc_handle_, gc_state_, last_key_block_handle_});
stop();

View file

@ -34,12 +34,13 @@ namespace validator {
class ValidatorManagerMasterchainReiniter : public td::actor::Actor {
public:
ValidatorManagerMasterchainReiniter(td::Ref<ValidatorManagerOptions> opts,
td::actor::ActorId<ValidatorManager> manager,
td::actor::ActorId<ValidatorManager> manager, td::actor::ActorId<Db> db,
td::Promise<ValidatorManagerInitResult> promise)
: opts_(std::move(opts)), manager_(manager), promise_(std::move(promise)) {
: opts_(std::move(opts)), manager_(manager), db_(db), promise_(std::move(promise)) {
block_id_ = opts_->init_block_id();
}
void start_up() override;
void written_hardforks();
void got_masterchain_handle(BlockHandle handle);
void download_proof_link();
void downloaded_proof_link(td::BufferSlice data);
@ -70,6 +71,7 @@ class ValidatorManagerMasterchainReiniter : public td::actor::Actor {
std::vector<ShardIdFull> shards_;
td::actor::ActorId<ValidatorManager> manager_;
td::actor::ActorId<Db> db_;
td::Promise<ValidatorManagerInitResult> promise_;
@ -95,6 +97,14 @@ class ValidatorManagerMasterchainStarter : public td::actor::Actor {
void got_gc_block_state(td::Ref<MasterchainState> state);
void got_key_block_handle(BlockHandle handle);
void got_shard_block_id(BlockIdExt block_id);
void got_hardforks(std::vector<BlockIdExt> hardforks);
void got_truncate_block_id(BlockIdExt block_id);
void got_truncate_block_handle(BlockHandle handle);
void got_truncate_state(td::Ref<MasterchainState> state);
void truncated_db();
void got_prev_key_block_handle(BlockHandle handle);
void truncated();
void written_next();
void finish();
private:
@ -112,6 +122,7 @@ class ValidatorManagerMasterchainStarter : public td::actor::Actor {
td::Promise<ValidatorManagerInitResult> promise_;
BlockIdExt client_block_id_;
td::actor::ActorOwn<ShardClient> client_;
};

View file

@ -52,29 +52,52 @@ void ValidatorManagerImpl::validate_block_is_next_proof(BlockIdExt prev_block_id
td::Status::Error(ErrorCode::protoviolation, "validate_block_is_next_proof() can only work for masterchain"));
return;
}
if (prev_block_id.seqno() + 1 != next_block_id.seqno()) {
VLOG(VALIDATOR_NOTICE) << "prev=" << prev_block_id << " next=" << next_block_id;
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "validate_block_is_next_proof(): bad seqno"));
return;
}
CHECK(last_masterchain_state_.not_null());
auto pp = create_proof(next_block_id, std::move(proof));
if (pp.is_error()) {
promise.set_error(pp.move_as_error_prefix("failed to create proof: "));
return;
}
auto P =
td::PromiseCreator::lambda([promise = std::move(promise), id = prev_block_id](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
return;
}
auto handle = R.move_as_ok();
CHECK(!handle->merge_before());
if (handle->one_prev(true) != id) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "prev block mismatch"));
return;
}
promise.set_value(td::Unit());
});
if (last_masterchain_seqno_ == prev_block_id.seqno()) {
CHECK(last_masterchain_block_id_ == prev_block_id);
run_check_proof_query(next_block_id, pp.move_as_ok(), actor_id(this), td::Timestamp::in(2.0), std::move(P),
opts_->is_hardfork(next_block_id));
auto P = td::PromiseCreator::lambda(
[promise = std::move(promise), id = prev_block_id](td::Result<BlockHandle> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
return;
}
auto handle = R.move_as_ok();
CHECK(!handle->merge_before());
if (handle->one_prev(true) != id) {
promise.set_error(td::Status::Error(ErrorCode::protoviolation, "prev block mismatch"));
return;
}
promise.set_value(td::Unit());
});
run_check_proof_query(next_block_id, pp.move_as_ok(), actor_id(this), td::Timestamp::in(2.0), std::move(P),
last_masterchain_state_, opts_->is_hardfork(next_block_id));
} else {
auto P =
td::PromiseCreator::lambda([promise = std::move(promise), next_block_id](td::Result<BlockHandle> R) mutable {
R.ensure();
auto handle = R.move_as_ok();
CHECK(handle->inited_next_left());
if (handle->one_next(true) == next_block_id) {
promise.set_value(td::Unit());
} else {
promise.set_error(td::Status::Error("next block id mismatch"));
}
});
get_block_handle(prev_block_id, false, std::move(P));
}
}
void ValidatorManagerImpl::validate_block_proof(BlockIdExt block_id, td::BufferSlice proof,
@ -468,7 +491,27 @@ void ValidatorManagerImpl::run_ext_query(td::BufferSlice data, td::Promise<td::B
promise.set_value(std::move(data));
});
run_liteserver_query(std::move(data), actor_id(this), lite_server_cache_.get(), std::move(P));
auto E = fetch_tl_prefix<lite_api::liteServer_waitMasterchainSeqno>(data, true);
if (E.is_error()) {
run_liteserver_query(std::move(data), actor_id(this), lite_server_cache_.get(), std::move(P));
} else {
auto e = E.move_as_ok();
if (static_cast<BlockSeqno>(e->seqno_) <= min_confirmed_masterchain_seqno_) {
run_liteserver_query(std::move(data), actor_id(this), lite_server_cache_.get(), std::move(P));
} else {
auto t = e->timeout_ms_ < 10000 ? e->timeout_ms_ * 0.001 : 10.0;
auto Q =
td::PromiseCreator::lambda([data = std::move(data), SelfId = actor_id(this), cache = lite_server_cache_.get(),
promise = std::move(P)](td::Result<td::Unit> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
return;
}
run_liteserver_query(std::move(data), SelfId, cache, std::move(promise));
});
wait_shard_client_state(e->seqno_, td::Timestamp::in(t), std::move(Q));
}
}
}
void ValidatorManagerImpl::wait_block_state(BlockHandle handle, td::uint32 priority, td::Timestamp timeout,
@ -1387,7 +1430,8 @@ void ValidatorManagerImpl::new_masterchain_block() {
}
void ValidatorManagerImpl::update_shards() {
if (last_masterchain_state_->rotated_all_shards() || last_masterchain_seqno_ == 0) {
if ((last_masterchain_state_->rotated_all_shards() || last_masterchain_seqno_ == 0) &&
opts_->get_last_fork_masterchain_seqno() <= last_masterchain_seqno_) {
allow_validate_ = true;
}
auto exp_vec = last_masterchain_state_->get_shards();
@ -1468,7 +1512,7 @@ void ValidatorManagerImpl::update_shards() {
auto val_set = last_masterchain_state_->get_validator_set(shard);
auto x = val_set->export_vector();
auto validator_id = get_validator(val_set);
auto validator_id = get_validator(shard, val_set);
if (!validator_id.is_zero()) {
auto val_group_id = get_validator_set_id(shard, val_set, opts_hash);
@ -1499,7 +1543,7 @@ void ValidatorManagerImpl::update_shards() {
for (auto &shard : future_shards) {
auto val_set = last_masterchain_state_->get_next_validator_set(shard);
auto validator_id = get_validator(val_set);
auto validator_id = get_validator(shard, val_set);
if (!validator_id.is_zero()) {
auto val_group_id = get_validator_set_id(shard, val_set, opts_hash);
auto it = next_validator_groups_.find(val_group_id);
@ -1548,7 +1592,7 @@ void ValidatorManagerImpl::update_shards() {
});
td::actor::send_closure(db_, &Db::update_destroyed_validator_sessions, gc_list_, std::move(P));
}
}
} // namespace validator
void ValidatorManagerImpl::written_destroyed_validator_sessions(std::vector<td::actor::ActorId<ValidatorGroup>> list) {
for (auto &v : list) {
@ -1609,7 +1653,7 @@ td::actor::ActorOwn<ValidatorGroup> ValidatorManagerImpl::create_validator_group
if (check_gc_list_.count(session_id) == 1) {
return td::actor::ActorOwn<ValidatorGroup>{};
} else {
auto validator_id = get_validator(validator_set);
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,
opts, keyring_, adnl_, rldp_, overlays_, db_root_, actor_id(this),
@ -1827,10 +1871,26 @@ void ValidatorManagerImpl::advance_gc(BlockHandle handle, td::Ref<MasterchainSta
try_advance_gc_masterchain_block();
}
void ValidatorManagerImpl::update_shard_client_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) {
auto seqno = handle->id().seqno();
shard_client_update(seqno);
promise.set_value(td::Unit());
}
void ValidatorManagerImpl::shard_client_update(BlockSeqno seqno) {
if (min_confirmed_masterchain_seqno_ < seqno) {
min_confirmed_masterchain_seqno_ = seqno;
}
while (shard_client_waiters_.size() > 0) {
auto it = shard_client_waiters_.begin();
if (it->first > seqno) {
break;
}
for (auto &y : it->second.waiting_) {
y.promise.set_value(td::Unit());
}
shard_client_waiters_.erase(it);
}
}
void ValidatorManagerImpl::state_serializer_update(BlockSeqno seqno) {
@ -1870,6 +1930,9 @@ void ValidatorManagerImpl::alarm() {
for (auto &w : wait_state_) {
w.second.check_timers();
}
for (auto &w : shard_client_waiters_) {
w.second.check_timers();
}
}
alarm_timestamp().relax(check_waiters_at_);
if (check_shard_clients_.is_in_past()) {
@ -1904,8 +1967,12 @@ void ValidatorManagerImpl::update_shard_client_state(BlockIdExt masterchain_bloc
td::actor::send_closure(db_, &Db::update_shard_client_state, masterchain_block_id, std::move(promise));
}
void ValidatorManagerImpl::get_shard_client_state(td::Promise<BlockIdExt> promise) {
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
void ValidatorManagerImpl::get_shard_client_state(bool from_db, td::Promise<BlockIdExt> promise) {
if (!shard_client_.empty() && !from_db) {
td::actor::send_closure(shard_client_, &ShardClient::get_processed_masterchain_block_id, std::move(promise));
} else {
td::actor::send_closure(db_, &Db::get_shard_client_state, std::move(promise));
}
}
void ValidatorManagerImpl::subscribe_to_shard(ShardIdFull shard) {
@ -1928,7 +1995,10 @@ bool ValidatorManagerImpl::is_validator() {
return temp_keys_.size() > 0 || permanent_keys_.size() > 0;
}
PublicKeyHash ValidatorManagerImpl::get_validator(td::Ref<ValidatorSet> val_set) {
PublicKeyHash ValidatorManagerImpl::get_validator(ShardIdFull shard, td::Ref<ValidatorSet> val_set) {
if (!opts_->need_validate(shard)) {
return PublicKeyHash::zero();
}
for (auto &key : temp_keys_) {
if (val_set->is_validator(key.bits256_value())) {
return key;
@ -2017,6 +2087,28 @@ void ValidatorManagerImpl::prepare_stats(td::Promise<std::vector<std::pair<std::
td::actor::send_closure(db_, &Db::prepare_stats, merger.make_promise("db."));
}
void ValidatorManagerImpl::truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) {
td::actor::send_closure(db_, &Db::truncate, std::move(state), std::move(promise));
}
void ValidatorManagerImpl::wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout,
td::Promise<td::Unit> promise) {
if (seqno <= min_confirmed_masterchain_seqno_) {
promise.set_value(td::Unit());
return;
}
if (timeout.is_in_past()) {
promise.set_error(td::Status::Error(ErrorCode::timeout, "timeout"));
return;
}
if (seqno > min_confirmed_masterchain_seqno_ + 100) {
promise.set_error(td::Status::Error(ErrorCode::notready, "too big masterchain block seqno"));
return;
}
shard_client_waiters_[seqno].waiting_.emplace_back(timeout, 0, std::move(promise));
}
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

@ -143,6 +143,8 @@ class ValidatorManagerImpl : public ValidatorManager {
std::vector<Waiter<ResType>> waiting_;
td::actor::ActorId<ActorT> actor_;
WaitList() = default;
std::pair<td::Timestamp, td::uint32> get_timeout() const {
td::Timestamp t = td::Timestamp::now();
td::uint32 prio = 0;
@ -256,6 +258,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void advance_gc(BlockHandle handle, td::Ref<MasterchainState> state);
void try_advance_gc_masterchain_block();
void update_gc_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
void update_shard_client_block_handle(BlockHandle handle, td::Promise<td::Unit> promise) override;
public:
void install_callback(std::unique_ptr<Callback> new_callback, td::Promise<td::Unit> promise) override {
@ -414,7 +417,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void send_block_broadcast(BlockBroadcast broadcast) override;
void update_shard_client_state(BlockIdExt masterchain_block_id, td::Promise<td::Unit> promise) override;
void get_shard_client_state(td::Promise<BlockIdExt> 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;
@ -448,7 +451,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void read_gc_list(std::vector<ValidatorSessionId> list);
bool is_validator();
PublicKeyHash get_validator(td::Ref<ValidatorSet> val_set);
PublicKeyHash get_validator(ShardIdFull shard, td::Ref<ValidatorSet> val_set);
ValidatorManagerImpl(td::Ref<ValidatorManagerOptions> opts, std::string db_root,
td::actor::ActorId<keyring::Keyring> keyring, td::actor::ActorId<adnl::Adnl> adnl,
@ -502,6 +505,10 @@ class ValidatorManagerImpl : public ValidatorManager {
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override;
void truncate(td::Ref<MasterchainState> state, td::Promise<td::Unit> promise) override;
void wait_shard_client_state(BlockSeqno seqno, td::Timestamp timeout, td::Promise<td::Unit> promise) override;
private:
td::Timestamp resend_shard_blocks_at_;
td::Timestamp check_waiters_at_;
@ -558,6 +565,9 @@ class ValidatorManagerImpl : public ValidatorManager {
double block_ttl() const {
return opts_->block_ttl();
}
private:
std::map<BlockSeqno, WaitList<td::actor::Actor, td::Unit>> shard_client_waiters_;
};
} // namespace validator

View file

@ -36,7 +36,7 @@ void ShardClient::start_up() {
R.ensure();
td::actor::send_closure(SelfId, &ShardClient::got_state_from_db, R.move_as_ok());
});
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, std::move(P));
td::actor::send_closure(manager_, &ValidatorManager::get_shard_client_state, true, std::move(P));
}
void ShardClient::got_state_from_db(BlockIdExt state) {
@ -94,6 +94,8 @@ void ShardClient::saved_to_db() {
}
CHECK(masterchain_block_handle_);
td::actor::send_closure(manager_, &ValidatorManager::update_shard_client_block_handle, masterchain_block_handle_,
[](td::Unit) {});
if (masterchain_block_handle_->inited_next_left()) {
new_masterchain_block_id(masterchain_block_handle_->one_next(true));
} else {
@ -198,6 +200,14 @@ void ShardClient::get_processed_masterchain_block(td::Promise<BlockSeqno> promis
promise.set_result(seqno);
}
void ShardClient::get_processed_masterchain_block_id(td::Promise<BlockIdExt> promise) {
if (masterchain_block_handle_) {
promise.set_result(masterchain_block_handle_->id());
} else {
promise.set_error(td::Status::Error(ErrorCode::notready, "shard client not started"));
}
}
void ShardClient::build_shard_overlays() {
auto v = masterchain_state_->get_shards();

View file

@ -88,6 +88,7 @@ class ShardClient : public td::actor::Actor {
void new_masterchain_block_notification(BlockHandle handle, td::Ref<MasterchainState> state);
void get_processed_masterchain_block(td::Promise<BlockSeqno> promise);
void get_processed_masterchain_block_id(td::Promise<BlockIdExt> promise);
};
} // namespace validator

View file

@ -25,7 +25,7 @@ namespace ton {
namespace validator {
td::Ref<ValidatorManagerOptions> ValidatorManagerOptions::create(
BlockIdExt zero_block_id, BlockIdExt init_block_id, std::function<bool(ShardIdFull)> check_shard,
BlockIdExt zero_block_id, BlockIdExt init_block_id, std::function<bool(ShardIdFull, ShardCheckMode)> check_shard,
bool allow_blockchain_init, td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration archive_ttl, td::ClocksBase::Duration key_proof_ttl,
bool initial_sync_disabled) {

View file

@ -33,7 +33,10 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
return init_block_id_;
}
bool need_monitor(ShardIdFull shard) const override {
return check_shard_(shard);
return check_shard_(shard, ShardCheckMode::m_monitor);
}
bool need_validate(ShardIdFull shard) const override {
return check_shard_(shard, ShardCheckMode::m_validate);
}
bool allow_blockchain_init() const override {
return allow_blockchain_init_;
@ -82,6 +85,9 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
td::uint32 get_last_fork_masterchain_seqno() const override {
return hardforks_.size() ? hardforks_.rbegin()->seqno() : 0;
}
std::vector<BlockIdExt> get_hardforks() const override {
return hardforks_;
}
td::uint32 get_filedb_depth() const override {
return db_depth_;
}
@ -92,7 +98,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)> check_shard) override {
void set_shard_check_function(std::function<bool(ShardIdFull, ShardCheckMode)> check_shard) override {
check_shard_ = std::move(check_shard);
}
void set_allow_blockchain_init(bool value) override {
@ -129,7 +135,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
}
ValidatorManagerOptionsImpl(BlockIdExt zero_block_id, BlockIdExt init_block_id,
std::function<bool(ShardIdFull)> check_shard, bool allow_blockchain_init,
std::function<bool(ShardIdFull, ShardCheckMode)> check_shard, bool allow_blockchain_init,
td::ClocksBase::Duration sync_blocks_before, td::ClocksBase::Duration block_ttl,
td::ClocksBase::Duration state_ttl, td::ClocksBase::Duration archive_ttl,
td::ClocksBase::Duration key_proof_ttl, bool initial_sync_disabled)
@ -148,7 +154,7 @@ struct ValidatorManagerOptionsImpl : public ValidatorManagerOptions {
private:
BlockIdExt zero_block_id_;
BlockIdExt init_block_id_;
std::function<bool(ShardIdFull)> check_shard_;
std::function<bool(ShardIdFull, ShardCheckMode)> check_shard_;
bool allow_blockchain_init_;
td::ClocksBase::Duration sync_blocks_before_;
td::ClocksBase::Duration block_ttl_;

View file

@ -46,9 +46,12 @@ class DownloadToken {
struct ValidatorManagerOptions : public td::CntObject {
public:
enum class ShardCheckMode { m_monitor, m_validate };
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) const = 0;
virtual bool allow_blockchain_init() const = 0;
virtual td::ClocksBase::Duration sync_blocks_before() const = 0;
virtual td::ClocksBase::Duration block_ttl() const = 0;
@ -60,6 +63,7 @@ struct ValidatorManagerOptions : public td::CntObject {
virtual td::uint32 get_vertical_seqno(BlockSeqno seqno) const = 0;
virtual td::uint32 get_maximal_vertical_seqno() const = 0;
virtual td::uint32 get_last_fork_masterchain_seqno() const = 0;
virtual std::vector<BlockIdExt> get_hardforks() const = 0;
virtual td::uint32 get_filedb_depth() const = 0;
virtual td::uint32 key_block_utime_step() const {
return 86400;
@ -67,7 +71,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)> check_shard) = 0;
virtual void set_shard_check_function(std::function<bool(ShardIdFull, ShardCheckMode)> check_shard) = 0;
virtual void set_allow_blockchain_init(bool value) = 0;
virtual void set_sync_blocks_before(td::ClocksBase::Duration value) = 0;
virtual void set_block_ttl(td::ClocksBase::Duration value) = 0;
@ -80,7 +84,7 @@ struct ValidatorManagerOptions : public td::CntObject {
static td::Ref<ValidatorManagerOptions> create(
BlockIdExt zero_block_id, BlockIdExt init_block_id,
std::function<bool(ShardIdFull)> check_shard = [](ShardIdFull) { return true; },
std::function<bool(ShardIdFull, ShardCheckMode)> check_shard = [](ShardIdFull, ShardCheckMode) { return true; },
bool allow_blockchain_init = false, td::ClocksBase::Duration sync_blocks_before = 300,
td::ClocksBase::Duration block_ttl = 86400 * 7, td::ClocksBase::Duration state_ttl = 3600,
td::ClocksBase::Duration archive_ttl = 86400 * 365, td::ClocksBase::Duration key_proof_ttl = 86400 * 3650,