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

Merge branch 'testnet' into block-generation

# Conflicts:
#	adnl/adnl-query.cpp
#	crypto/block/block.tlb
#	crypto/block/mc-config.h
#	lite-client/lite-client.cpp
#	overlay/overlay-manager.h
#	overlay/overlay-peers.cpp
#	overlay/overlay.cpp
#	overlay/overlay.h
#	overlay/overlay.hpp
#	overlay/overlays.h
#	rldp-http-proxy/DNSResolver.cpp
#	rldp-http-proxy/rldp-http-proxy.cpp
#	tl/generate/scheme/ton_api.tl
#	tl/generate/scheme/ton_api.tlo
#	tl/generate/scheme/tonlib_api.tlo
#	ton/ton-types.h
#	tonlib/tonlib/ExtClient.cpp
#	tonlib/tonlib/ExtClient.h
#	tonlib/tonlib/ExtClientLazy.cpp
#	tonlib/tonlib/ExtClientOutbound.h
#	tonlib/tonlib/ExtClientRaw.h
#	tonlib/tonlib/TonlibClient.cpp
#	tonlib/tonlib/TonlibClient.h
#	tonlib/tonlib/tonlib-cli.cpp
#	validator/impl/collator.cpp
#	validator/impl/validate-query.cpp
#	validator/impl/validate-query.hpp
#	validator/manager.cpp
#	validator/state-serializer.cpp
#	validator/state-serializer.hpp
#	validator/validator-group.cpp
#	validator/validator-group.hpp
#	validator/validator.h
This commit is contained in:
SpyCheese 2022-12-22 23:37:35 +03:00
commit d652f7d706
200 changed files with 13492 additions and 2997 deletions

View file

@ -441,7 +441,10 @@ void ArchiveManager::get_block_by_unix_time(AccountIdPrefixFull account_id, Unix
td::Promise<ConstBlockHandle> promise) {
auto f = get_file_desc_by_unix_time(account_id, ts, false);
if (f) {
auto n = get_next_file_desc(f);
auto n = f;
do {
n = get_next_file_desc(n);
} while (n != nullptr && !n->has_account_prefix(account_id));
td::actor::ActorId<ArchiveSlice> aid;
if (n) {
aid = n->file_actor_id();
@ -464,7 +467,10 @@ void ArchiveManager::get_block_by_lt(AccountIdPrefixFull account_id, LogicalTime
td::Promise<ConstBlockHandle> promise) {
auto f = get_file_desc_by_lt(account_id, lt, false);
if (f) {
auto n = get_next_file_desc(f);
auto n = f;
do {
n = get_next_file_desc(n);
} while (n != nullptr && !n->has_account_prefix(account_id));
td::actor::ActorId<ArchiveSlice> aid;
if (n) {
aid = n->file_actor_id();
@ -1232,6 +1238,16 @@ void ArchiveManager::truncate(BlockSeqno masterchain_seqno, ConstBlockHandle han
}
}
bool ArchiveManager::FileDescription::has_account_prefix(AccountIdPrefixFull account_id) const {
for (int i = 0; i < 60; i++) {
auto shard = shard_prefix(account_id, i);
if (first_blocks.count(shard)) {
return true;
}
}
return false;
}
} // namespace validator
} // namespace ton

View file

@ -97,6 +97,7 @@ class ArchiveManager : public td::actor::Actor {
void clear_actor_id() {
file.reset();
}
bool has_account_prefix(AccountIdPrefixFull account_id) const;
PackageId id;
bool deleted;

View file

@ -42,13 +42,15 @@ td::Result<BlockHandle> create_block_handle(td::BufferSlice data);
td::Result<BlockHandle> create_block_handle(td::Slice data);
td::Result<ConstBlockHandle> create_temp_block_handle(td::BufferSlice data);
BlockHandle create_empty_block_handle(BlockIdExt id);
td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data);
td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data,
block::SizeLimitsConfig::ExtMsgLimits limits);
td::Result<td::Ref<IhrMessage>> create_ihr_message(td::BufferSlice data);
td::Result<std::vector<td::Ref<ShardTopBlockDescription>>> create_new_shard_block_descriptions(td::BufferSlice data);
td::Ref<BlockSignatureSet> create_signature_set(std::vector<BlockSignature> sig_set);
void run_check_external_message(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise);
void run_check_external_message(td::BufferSlice data, block::SizeLimitsConfig::ExtMsgLimits limits,
td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Ref<ExtMessage>> promise);
void run_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures,

View file

@ -144,7 +144,14 @@ void FullNodeShardImpl::check_broadcast(PublicKeyHash src, td::BufferSlice broad
auto q = B.move_as_ok();
td::actor::send_closure(validator_manager_, &ValidatorManagerInterface::check_external_message,
std::move(q->message_->data_), std::move(promise));
std::move(q->message_->data_),
[promise = std::move(promise)](td::Result<td::Ref<ExtMessage>> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
promise.set_result(td::Unit());
}
});
}
void FullNodeShardImpl::remove_neighbour(adnl::AdnlNodeIdShort id) {

View file

@ -72,6 +72,7 @@ class Collator final : public td::actor::Actor {
Ref<ValidatorSet> validator_set_;
td::actor::ActorId<ValidatorManager> manager;
td::Timestamp timeout;
td::Timestamp soft_timeout_, medium_timeout_;
td::Promise<BlockCandidate> main_promise;
ton::BlockSeqno last_block_seqno{0};
ton::BlockSeqno prev_mc_block_seqno{0};

View file

@ -66,10 +66,12 @@ Collator::Collator(ShardIdFull shard, bool is_hardfork, BlockIdExt min_mastercha
, validator_set_(std::move(validator_set))
, manager(manager)
, timeout(timeout)
, soft_timeout_(td::Timestamp::at(timeout.at() - 3.0))
, medium_timeout_(td::Timestamp::at(timeout.at() - 1.5))
, main_promise(std::move(promise))
, perf_timer_("collate", 0.1, [manager](double duration) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "collate", duration);
}) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "collate", duration);
}) {
}
void Collator::start_up() {
@ -1592,30 +1594,22 @@ bool Collator::init_lt() {
}
bool Collator::fetch_config_params() {
auto res = impl_fetch_config_params(std::move(config_),
&old_mparams_, &storage_prices_, &storage_phase_cfg_,
&rand_seed_, &compute_phase_cfg_, &action_phase_cfg_,
&masterchain_create_fee_, &basechain_create_fee_,
workchain()
);
auto res = impl_fetch_config_params(std::move(config_), &old_mparams_, &storage_prices_, &storage_phase_cfg_,
&rand_seed_, &compute_phase_cfg_, &action_phase_cfg_, &masterchain_create_fee_,
&basechain_create_fee_, workchain());
if (res.is_error()) {
return fatal_error(res.move_as_error());
return fatal_error(res.move_as_error());
}
config_ = res.move_as_ok();
return true;
}
td::Result<std::unique_ptr<block::ConfigInfo>>
Collator::impl_fetch_config_params(std::unique_ptr<block::ConfigInfo> config,
Ref<vm::Cell>* old_mparams,
std::vector<block::StoragePrices>* storage_prices,
block::StoragePhaseConfig* storage_phase_cfg,
td::BitArray<256>* rand_seed,
block::ComputePhaseConfig* compute_phase_cfg,
block::ActionPhaseConfig* action_phase_cfg,
td::RefInt256* masterchain_create_fee,
td::RefInt256* basechain_create_fee,
WorkchainId wc) {
td::Result<std::unique_ptr<block::ConfigInfo>> Collator::impl_fetch_config_params(
std::unique_ptr<block::ConfigInfo> config, Ref<vm::Cell>* old_mparams,
std::vector<block::StoragePrices>* storage_prices, block::StoragePhaseConfig* storage_phase_cfg,
td::BitArray<256>* rand_seed, block::ComputePhaseConfig* compute_phase_cfg,
block::ActionPhaseConfig* action_phase_cfg, td::RefInt256* masterchain_create_fee,
td::RefInt256* basechain_create_fee, WorkchainId wc) {
*old_mparams = config->get_config_param(9);
{
auto res = config->get_storage_prices();
@ -1629,6 +1623,7 @@ td::Result<std::unique_ptr<block::ConfigInfo>>
prng::rand_gen().strong_rand_bytes(rand_seed->data(), 32);
LOG(DEBUG) << "block random seed set to " << rand_seed->to_hex();
}
TRY_RESULT(size_limits, config->get_size_limits_config());
{
// compute compute_phase_cfg / storage_phase_cfg
auto cell = config->get_config_param(wc == ton::masterchainId ? 20 : 21);
@ -1641,6 +1636,7 @@ td::Result<std::unique_ptr<block::ConfigInfo>>
}
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->max_vm_data_depth = size_limits.max_vm_data_depth;
compute_phase_cfg->global_config = config->get_root_cell();
}
{
@ -1662,6 +1658,7 @@ td::Result<std::unique_ptr<block::ConfigInfo>>
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
action_phase_cfg->workchains = &config->get_workchain_list();
action_phase_cfg->bounce_msg_body = (config->has_capability(ton::capBounceMsgBody) ? 256 : 0);
action_phase_cfg->size_limits = size_limits;
}
{
// fetch block_grams_created
@ -1761,6 +1758,9 @@ bool Collator::init_value_create() {
}
bool Collator::do_collate() {
// After do_collate started it will not be interrupted by timeout
alarm_timestamp() = td::Timestamp::never();
LOG(DEBUG) << "do_collate() : start";
if (!fetch_config_params()) {
return fatal_error("cannot fetch required configuration parameters from masterchain state");
@ -2278,15 +2278,11 @@ Ref<vm::Cell> Collator::create_ordinary_transaction(Ref<vm::Cell> msg_root) {
block::Account* acc = acc_res.move_as_ok();
assert(acc);
auto res = impl_create_ordinary_transaction(msg_root, acc, now_, start_lt,
&storage_phase_cfg_, &compute_phase_cfg_,
&action_phase_cfg_,
external, last_proc_int_msg_.first
);
if(res.is_error()) {
auto res = impl_create_ordinary_transaction(msg_root, acc, now_, start_lt, &storage_phase_cfg_, &compute_phase_cfg_,
&action_phase_cfg_, external, last_proc_int_msg_.first);
if (res.is_error()) {
auto error = res.move_as_error();
if(error.code() == -701) {
if (error.code() == -701) {
// ignorable errors
LOG(DEBUG) << error.message();
return {};
@ -2313,16 +2309,13 @@ Ref<vm::Cell> Collator::create_ordinary_transaction(Ref<vm::Cell> msg_root) {
// If td::status::error_code == 669 - Fatal Error block can not be produced
// if td::status::error_code == 701 - Transaction can not be included into block, but it's ok (external or too early internal)
td::Result<std::unique_ptr<block::Transaction>> Collator::impl_create_ordinary_transaction(Ref<vm::Cell> msg_root,
block::Account* acc,
UnixTime utime, LogicalTime lt,
block::StoragePhaseConfig* storage_phase_cfg,
block::ComputePhaseConfig* compute_phase_cfg,
block::ActionPhaseConfig* action_phase_cfg,
bool external, LogicalTime after_lt) {
td::Result<std::unique_ptr<block::Transaction>> Collator::impl_create_ordinary_transaction(
Ref<vm::Cell> msg_root, block::Account* acc, UnixTime utime, LogicalTime lt,
block::StoragePhaseConfig* storage_phase_cfg, block::ComputePhaseConfig* compute_phase_cfg,
block::ActionPhaseConfig* action_phase_cfg, bool external, LogicalTime after_lt) {
if (acc->last_trans_end_lt_ >= lt && acc->transactions.empty()) {
return td::Status::Error(-669, PSTRING() << "last transaction time in the state of account " << acc->workchain << ":" << acc->addr.to_hex()
<< " is too large");
return td::Status::Error(-669, PSTRING() << "last transaction time in the state of account " << acc->workchain
<< ":" << acc->addr.to_hex() << " is too large");
}
auto trans_min_lt = lt;
if (external) {
@ -2336,51 +2329,58 @@ td::Result<std::unique_ptr<block::Transaction>> Collator::impl_create_ordinary_t
if (!trans->unpack_input_msg(ihr_delivered, action_phase_cfg)) {
if (external) {
// inbound external message was not accepted
return td::Status::Error(-701,"inbound external message rejected by account "s + acc->addr.to_hex() +
" before smart-contract execution");
}
return td::Status::Error(-669,"cannot unpack input message for a new transaction");
return td::Status::Error(-701, "inbound external message rejected by account "s + acc->addr.to_hex() +
" before smart-contract execution");
}
return td::Status::Error(-669, "cannot unpack input message for a new transaction");
}
if (trans->bounce_enabled) {
if (!trans->prepare_storage_phase(*storage_phase_cfg, true)) {
return td::Status::Error(-669,"cannot create storage phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
return td::Status::Error(
-669, "cannot create storage phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (!external && !trans->prepare_credit_phase()) {
return td::Status::Error(-669,"cannot create credit phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
return td::Status::Error(
-669, "cannot create credit phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
} else {
if (!external && !trans->prepare_credit_phase()) {
return td::Status::Error(-669,"cannot create credit phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
return td::Status::Error(
-669, "cannot create credit phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (!trans->prepare_storage_phase(*storage_phase_cfg, true, true)) {
return td::Status::Error(-669,"cannot create storage phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
return td::Status::Error(
-669, "cannot create storage phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
}
if (!trans->prepare_compute_phase(*compute_phase_cfg)) {
return td::Status::Error(-669,"cannot create compute phase of a new transaction for smart contract "s + acc->addr.to_hex());
return td::Status::Error(
-669, "cannot create compute phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (!trans->compute_phase->accepted) {
if (external) {
// inbound external message was not accepted
auto const& cp = *trans->compute_phase;
return td::Status::Error(
-701,
PSLICE() << "inbound external message rejected by transaction " << acc->addr.to_hex() << ":\n" <<
"exitcode=" << cp.exit_code << ", steps=" << cp.vm_steps << ", gas_used=" << cp.gas_used <<
(cp.vm_log.empty() ? "" : "\nVM Log (truncated):\n..." + cp.vm_log));
} else if (trans->compute_phase->skip_reason == block::ComputePhase::sk_none) {
return td::Status::Error(-669,"new ordinary transaction for smart contract "s + acc->addr.to_hex() +
" has not been accepted by the smart contract (?)");
}
-701, PSLICE() << "inbound external message rejected by transaction " << acc->addr.to_hex() << ":\n"
<< "exitcode=" << cp.exit_code << ", steps=" << cp.vm_steps << ", gas_used=" << cp.gas_used
<< (cp.vm_log.empty() ? "" : "\nVM Log (truncated):\n..." + cp.vm_log));
} else if (trans->compute_phase->skip_reason == block::ComputePhase::sk_none) {
return td::Status::Error(-669, "new ordinary transaction for smart contract "s + acc->addr.to_hex() +
" has not been accepted by the smart contract (?)");
}
}
if (trans->compute_phase->success && !trans->prepare_action_phase(*action_phase_cfg)) {
return td::Status::Error(-669,"cannot create action phase of a new transaction for smart contract "s + acc->addr.to_hex());
return td::Status::Error(
-669, "cannot create action phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (trans->bounce_enabled && !trans->compute_phase->success && !trans->prepare_bounce_phase(*action_phase_cfg)) {
return td::Status::Error(-669,"cannot create bounce phase of a new transaction for smart contract "s + acc->addr.to_hex());
if (trans->bounce_enabled && (!trans->compute_phase->success || trans->action_phase->state_size_too_big) &&
!trans->prepare_bounce_phase(*action_phase_cfg)) {
return td::Status::Error(
-669, "cannot create bounce phase of a new transaction for smart contract "s + acc->addr.to_hex());
}
if (!trans->serialize()) {
return td::Status::Error(-669,"cannot serialize new transaction for smart contract "s + acc->addr.to_hex());
return td::Status::Error(-669, "cannot serialize new transaction for smart contract "s + acc->addr.to_hex());
}
return std::move(trans);
}
@ -2536,6 +2536,11 @@ int Collator::process_one_new_message(block::NewOutMsg msg, bool enqueue_only, R
block_full_ = true;
return 3;
}
if (soft_timeout_.is_in_past(td::Timestamp::now())) {
LOG(WARNING) << "soft timeout reached, stop processing new messages";
block_full_ = true;
return 3;
}
return 1;
}
@ -2816,6 +2821,11 @@ bool Collator::process_inbound_internal_messages() {
LOG(INFO) << "BLOCK FULL, stop processing inbound internal messages";
break;
}
if (soft_timeout_.is_in_past(td::Timestamp::now())) {
block_full_ = true;
LOG(WARNING) << "soft timeout reached, stop processing inbound internal messages";
break;
}
LOG(DEBUG) << "processing inbound message with (lt,hash)=(" << kv->lt << "," << kv->key.to_hex()
<< ") from neighbor #" << kv->source;
if (verbosity > 2) {
@ -2847,6 +2857,10 @@ bool Collator::process_inbound_external_messages() {
LOG(INFO) << "BLOCK FULL, stop processing external messages";
break;
}
if (medium_timeout_.is_in_past(td::Timestamp::now())) {
LOG(WARNING) << "medium timeout reached, stop processing inbound external messages";
break;
}
auto ext_msg = ext_msg_pair.first;
ton::Bits256 hash{ext_msg->get_hash().bits()};
int r = process_external_message(std::move(ext_msg));
@ -3126,7 +3140,7 @@ static int update_one_shard(block::McShardHash& info, const block::McShardHash*
if (info.is_fsm_none() && (info.want_split_ || depth < wc_info->min_split) && depth < wc_info->max_split &&
depth < 60) {
// prepare split
info.set_fsm_split(now + ton::split_merge_delay, ton::split_merge_interval);
info.set_fsm_split(now + wc_info->split_merge_delay, wc_info->split_merge_interval);
changed = true;
LOG(INFO) << "preparing to split shard " << info.shard().to_str() << " during " << info.fsm_utime() << " .. "
<< info.fsm_utime_end();
@ -3134,7 +3148,7 @@ static int update_one_shard(block::McShardHash& info, const block::McShardHash*
sibling && !sibling->before_split_ && sibling->is_fsm_none() &&
(sibling->want_merge_ || depth > wc_info->max_split)) {
// prepare merge
info.set_fsm_merge(now + ton::split_merge_delay, ton::split_merge_interval);
info.set_fsm_merge(now + wc_info->split_merge_delay, wc_info->split_merge_interval);
changed = true;
LOG(INFO) << "preparing to merge shard " << info.shard().to_str() << " with " << sibling->shard().to_str()
<< " during " << info.fsm_utime() << " .. " << info.fsm_utime_end();
@ -3216,7 +3230,7 @@ bool Collator::create_mc_state_extra() {
" contains an invalid configuration in its data, IGNORING CHANGES";
ignore_cfg_changes = true;
} else {
cfg0 = cfg_dict.lookup_ref(td::BitArray<32>{(long long) 0});
cfg0 = cfg_dict.lookup_ref(td::BitArray<32>{(long long)0});
}
bool changed_cfg = false;
if (cfg0.not_null()) {

View file

@ -38,8 +38,9 @@ ExtMessageQ::ExtMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, AccountId
hash_ = block::compute_file_hash(data_);
}
td::Result<Ref<ExtMessageQ>> ExtMessageQ::create_ext_message(td::BufferSlice data) {
if (data.size() > max_ext_msg_size) {
td::Result<Ref<ExtMessageQ>> ExtMessageQ::create_ext_message(td::BufferSlice data,
block::SizeLimitsConfig::ExtMsgLimits limits) {
if (data.size() > limits.max_size) {
return td::Status::Error("external message too large, rejecting");
}
vm::BagOfCells boc;
@ -54,7 +55,7 @@ td::Result<Ref<ExtMessageQ>> ExtMessageQ::create_ext_message(td::BufferSlice dat
if (ext_msg->get_level() != 0) {
return td::Status::Error("external message must have zero level");
}
if (ext_msg->get_depth() >= max_ext_msg_depth) {
if (ext_msg->get_depth() >= limits.max_depth) {
return td::Status::Error("external message is too deep");
}
vm::CellSlice cs{vm::NoVmOrd{}, ext_msg};
@ -85,21 +86,25 @@ td::Result<Ref<ExtMessageQ>> ExtMessageQ::create_ext_message(td::BufferSlice dat
return Ref<ExtMessageQ>{true, std::move(data), std::move(ext_msg), dest_prefix, wc, addr};
}
void ExtMessageQ::run_message(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<td::Unit> promise) {
auto R = create_ext_message(std::move(data));
void ExtMessageQ::run_message(td::BufferSlice data, block::SizeLimitsConfig::ExtMsgLimits limits,
td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<td::Ref<ExtMessage>> promise) {
auto R = create_ext_message(std::move(data), limits);
if (R.is_error()) {
return promise.set_error(R.move_as_error_prefix("failed to parse external message "));
}
auto M = R.move_as_ok();
auto root = M->root_cell();
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
tlb::unpack_cell_inexact(root, info); // checked in create message
tlb::unpack_cell_inexact(root, info); // checked in create message
ton::StdSmcAddress addr = M->addr();
ton::WorkchainId wc = M->wc();
run_fetch_account_state(wc, addr, manager,
[promise = std::move(promise), msg_root = root, wc = wc](td::Result<std::tuple<td::Ref<vm::CellSlice>,UnixTime,LogicalTime,std::unique_ptr<block::ConfigInfo>>> res) mutable {
run_fetch_account_state(
wc, addr, manager,
[promise = std::move(promise), msg_root = root, wc,
M](td::Result<std::tuple<td::Ref<vm::CellSlice>, UnixTime, LogicalTime, std::unique_ptr<block::ConfigInfo>>>
res) mutable {
if (res.is_error()) {
promise.set_error(td::Status::Error(PSLICE() << "Failed to get account state"));
} else {
@ -109,20 +114,19 @@ void ExtMessageQ::run_message(td::BufferSlice data, td::actor::ActorId<ton::vali
auto utime = std::get<1>(tuple);
auto lt = std::get<2>(tuple);
auto config = std::move(std::get<3>(tuple));
if(!acc.unpack(shard_acc, {}, utime, false)) {
if (!acc.unpack(shard_acc, {}, utime, false)) {
promise.set_error(td::Status::Error(PSLICE() << "Failed to unpack account state"));
} else {
auto status = run_message_on_account(wc, &acc, utime, lt + 1, msg_root, std::move(config));
if (status.is_ok()) {
promise.set_value(td::Unit());
promise.set_value(std::move(M));
} else {
promise.set_error(td::Status::Error(
PSLICE() << "External message was not accepted\n" << status.message()));
promise.set_error(td::Status::Error(PSLICE() << "External message was not accepted\n"
<< status.message()));
}
}
}
}
);
});
}
td::Status ExtMessageQ::run_message_on_account(ton::WorkchainId wc,

View file

@ -37,8 +37,6 @@ class ExtMessageQ : public ExtMessage {
ton::StdSmcAddress addr_;
public:
static constexpr unsigned max_ext_msg_size = 65535;
static constexpr unsigned max_ext_msg_depth = 512;
AccountIdPrefixFull shard() const override {
return addr_prefix_;
}
@ -59,10 +57,13 @@ class ExtMessageQ : public ExtMessage {
return addr_;
}
ExtMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, AccountIdPrefixFull shard, ton::WorkchainId wc, ton::StdSmcAddress addr);
static td::Result<td::Ref<ExtMessageQ>> create_ext_message(td::BufferSlice data);
static void run_message(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<td::Unit> promise);
ExtMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, AccountIdPrefixFull shard, ton::WorkchainId wc,
ton::StdSmcAddress addr);
static td::Result<td::Ref<ExtMessageQ>> create_ext_message(td::BufferSlice data,
block::SizeLimitsConfig::ExtMsgLimits limits);
static void run_message(td::BufferSlice data, block::SizeLimitsConfig::ExtMsgLimits limits,
td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<td::Ref<ExtMessage>> promise);
static td::Status run_message_on_account(ton::WorkchainId wc,
block::Account* acc,
UnixTime utime, LogicalTime lt,

View file

@ -111,13 +111,16 @@ td::Ref<BlockSignatureSet> create_signature_set(std::vector<BlockSignature> sig_
return td::Ref<BlockSignatureSetQ>{true, std::move(sig_set)};
}
td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data) {
TRY_RESULT(res, ExtMessageQ::create_ext_message(std::move(data)));
td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data,
block::SizeLimitsConfig::ExtMsgLimits limits) {
TRY_RESULT(res, ExtMessageQ::create_ext_message(std::move(data), limits));
return std::move(res);
}
void run_check_external_message(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager, td::Promise<td::Unit> promise) {
ExtMessageQ::run_message(std::move(data), std::move(manager), std::move(promise));
void run_check_external_message(td::BufferSlice data, block::SizeLimitsConfig::ExtMsgLimits limits,
td::actor::ActorId<ValidatorManager> manager,
td::Promise<td::Ref<ExtMessage>> promise) {
ExtMessageQ::run_message(std::move(data), limits, std::move(manager), std::move(promise));
}
td::Result<td::Ref<IhrMessage>> create_ihr_message(td::BufferSlice data) {

View file

@ -153,6 +153,10 @@ void LiteQuery::start_up() {
this->perform_getAccountState(ton::create_block_id(q.id_), static_cast<WorkchainId>(q.account_->workchain_),
q.account_->id_, 0);
},
[&](lite_api::liteServer_getAccountStatePrunned& q) {
this->perform_getAccountState(ton::create_block_id(q.id_), static_cast<WorkchainId>(q.account_->workchain_),
q.account_->id_, 0x40000000);
},
[&](lite_api::liteServer_getOneTransaction& q) {
this->perform_getOneTransaction(ton::create_block_id(q.id_),
static_cast<WorkchainId>(q.account_->workchain_), q.account_->id_,
@ -228,7 +232,7 @@ void LiteQuery::perform_getMasterchainInfo(int mode) {
return;
}
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
manager_, &ton::validator::ValidatorManager::get_last_liteserver_state_block,
[Self = actor_id(this), return_state = bool(acc_state_promise_), 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());
@ -482,20 +486,13 @@ void LiteQuery::perform_sendMessage(td::BufferSlice data) {
auto copy = data.clone();
td::actor::send_closure_later(
manager_, &ValidatorManager::check_external_message, std::move(copy),
[Self = actor_id(this), data = std::move(data), manager = manager_](td::Result<td::Unit> res) mutable {
[Self = actor_id(this), data = std::move(data), manager = manager_](td::Result<td::Ref<ExtMessage>> res) mutable {
if(res.is_error()) {
td::actor::send_closure(Self, &LiteQuery::abort_query,
res.move_as_error_prefix("cannot apply external message to current state : "s));
} else {
auto crm = ton::validator::create_ext_message(std::move(data));
if (crm.is_error()) {
//UNREACHABLE, checks in check_external_message,
td::actor::send_closure(Self, &LiteQuery::abort_query,
crm.move_as_error());
return;
}
LOG(INFO) << "sending an external message to validator manager";
td::actor::send_closure_later(manager, &ValidatorManager::send_external_message, crm.move_as_ok());
td::actor::send_closure_later(manager, &ValidatorManager::send_external_message, res.move_as_ok());
auto b = ton::create_serialize_tl_object<ton::lite_api::liteServer_sendMsgStatus>(1);
td::actor::send_closure(Self, &LiteQuery::finish_query, std::move(b));
}
@ -779,9 +776,9 @@ void LiteQuery::perform_getAccountState(BlockIdExt blkid, WorkchainId workchain,
set_continuation([&]() -> void { continue_getAccountState(); });
request_mc_block_data_state(blkid);
} else {
LOG(INFO) << "sending a get_top_masterchain_state_block query to manager";
LOG(INFO) << "sending a get_last_liteserver_state_block query to manager";
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
manager_, &ton::validator::ValidatorManager::get_last_liteserver_state_block,
[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());
@ -858,7 +855,7 @@ void LiteQuery::perform_getLibraries(std::vector<td::Bits256> library_list) {
sort( library_list.begin(), library_list.end() );
library_list.erase( unique( library_list.begin(), library_list.end() ), library_list.end() );
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
manager_, &ton::validator::ValidatorManager::get_last_liteserver_state_block,
[Self = actor_id(this), library_list](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());
@ -1213,6 +1210,19 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
}
td::BufferSlice data;
if (acc_root.not_null()) {
if (mode_ & 0x40000000) {
vm::MerkleProofBuilder mpb{acc_root};
// account_none$0 = Account;
// account$1 addr:MsgAddressInt storage_stat:StorageInfo storage:AccountStorage = Account;
// account_storage$_ last_trans_lt:uint64 balance:CurrencyCollection state:AccountState = AccountStorage;
// account_active$1 _:StateInit = AccountState;
auto S = mpb.root()->load_cell();
if (S.is_error()) {
fatal_error(S.move_as_error_prefix("Failed to load account: "));
return;
}
acc_root = mpb.extract_proof();
}
auto res = vm::std_boc_serialize(std::move(acc_root));
if (res.is_error()) {
fatal_error(res.move_as_error());
@ -1532,7 +1542,7 @@ void LiteQuery::perform_getShardInfo(BlockIdExt blkid, ShardIdFull shard, bool e
}
void LiteQuery::load_prevKeyBlock(ton::BlockIdExt blkid, td::Promise<std::pair<BlockIdExt, Ref<BlockQ>>> promise) {
td::actor::send_closure_later(manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
td::actor::send_closure_later(manager_, &ton::validator::ValidatorManager::get_last_liteserver_state_block,
[Self = actor_id(this), blkid, promise = std::move(promise)](
td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) mutable {
td::actor::send_closure_later(Self, &LiteQuery::continue_loadPrevKeyBlock, blkid,
@ -1955,7 +1965,7 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
});
} else {
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
manager_, &ton::validator::ValidatorManager::get_last_liteserver_state_block,
[Self = actor_id(this), from, to, 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());
@ -1968,7 +1978,7 @@ void LiteQuery::perform_getBlockProof(ton::BlockIdExt from, ton::BlockIdExt to,
}
} else if (mode & 2) {
td::actor::send_closure_later(
manager_, &ton::validator::ValidatorManager::get_top_masterchain_state_block,
manager_, &ton::validator::ValidatorManager::get_last_liteserver_state_block,
[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());

View file

@ -126,6 +126,10 @@ class MasterchainStateQ : public MasterchainState, public ShardStateQ {
ValidatorSessionConfig get_consensus_config() const override {
return config_->get_consensus_config();
}
block::SizeLimitsConfig::ExtMsgLimits get_ext_msg_limits() const override {
auto R = config_->get_size_limits_config();
return R.is_error() ? block::SizeLimitsConfig::ExtMsgLimits() : R.ok_ref().ext_msg_limits;
}
BlockIdExt last_key_block_id() const override;
BlockIdExt next_key_block_id(BlockSeqno seqno) const override;
BlockIdExt prev_key_block_id(BlockSeqno seqno) const override;

View file

@ -67,8 +67,8 @@ ValidateQuery::ValidateQuery(ShardIdFull shard, BlockIdExt min_masterchain_block
, shard_pfx_(shard_.shard)
, shard_pfx_len_(ton::shard_prefix_length(shard_))
, perf_timer_("validateblock", 0.1, [manager](double duration) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "validateblock", duration);
}) {
send_closure(manager, &ValidatorManager::add_perf_timer_stat, "validateblock", duration);
}) {
}
void ValidateQuery::alarm() {
@ -737,6 +737,8 @@ bool ValidateQuery::try_unpack_mc_state() {
return fatal_error(limits.move_as_error());
}
block_limits_ = limits.move_as_ok();
block_limits_->start_lt = start_lt_;
block_limit_status_ = std::make_unique<block::BlockLimitStatus>(*block_limits_);
if (!fetch_config_params()) {
return false;
}
@ -765,6 +767,14 @@ bool ValidateQuery::fetch_config_params() {
// recover (not generate) rand seed from block header
CHECK(!rand_seed_.is_zero());
}
block::SizeLimitsConfig size_limits;
{
auto res = config_->get_size_limits_config();
if (res.is_error()) {
return fatal_error(res.move_as_error());
}
size_limits = res.move_as_ok();
}
{
// compute compute_phase_cfg / storage_phase_cfg
auto cell = config_->get_config_param(is_masterchain() ? 20 : 21);
@ -777,6 +787,7 @@ bool ValidateQuery::fetch_config_params() {
}
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_.max_vm_data_depth = size_limits.max_vm_data_depth;
compute_phase_cfg_.global_config = config_->get_root_cell();
}
{
@ -798,6 +809,7 @@ bool ValidateQuery::fetch_config_params() {
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
action_phase_cfg_.workchains = &config_->get_workchain_list();
action_phase_cfg_.bounce_msg_body = (config_->has_capability(ton::capBounceMsgBody) ? 256 : 0);
action_phase_cfg_.size_limits = size_limits;
}
{
// fetch block_grams_created
@ -998,6 +1010,16 @@ bool ValidateQuery::compute_prev_state() {
return compute_prev_state_from_collated_data();
}
CHECK(prev_states.size() == 1u + after_merge_);
// Extend validator timeout if previous block is too old
UnixTime prev_ts = prev_states[0]->get_unix_time();
if (after_merge_) {
prev_ts = std::max(prev_ts, prev_states[1]->get_unix_time());
}
td::Timestamp new_timeout = td::Timestamp::in(std::min(60.0, (td::Clocks::system() - (double)prev_ts) / 2));
if (timeout < new_timeout) {
alarm_timestamp() = timeout = new_timeout;
}
prev_state_root_ = prev_states[0]->root_cell();
CHECK(prev_state_root_.not_null());
if (after_merge_) {
@ -1690,8 +1712,8 @@ bool ValidateQuery::check_one_shard(const block::McShardHash& info, const block:
(sibling->want_merge_ || depth > wc_info->max_split);
if (!fsm_inherited && !info.is_fsm_none()) {
if (info.fsm_utime() < now_ || info.fsm_utime_end() <= info.fsm_utime() ||
info.fsm_utime_end() < info.fsm_utime() + ton::min_split_merge_interval ||
info.fsm_utime_end() > now_ + ton::max_split_merge_delay) {
info.fsm_utime_end() < info.fsm_utime() + wc_info->min_split_merge_interval ||
info.fsm_utime_end() > now_ + wc_info->max_split_merge_delay) {
return reject_query(PSTRING() << "incorrect future split/merge interval " << info.fsm_utime() << " .. "
<< info.fsm_utime_end() << " set for shard " << shard.to_str()
<< " in new shard configuration (it is " << now_ << " now)");
@ -4183,6 +4205,9 @@ std::unique_ptr<block::Account> ValidateQuery::unpack_account(td::ConstBitPtr ad
bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalTime lt, Ref<vm::Cell> trans_root,
bool is_first, bool is_last) {
if (!check_timeout()) {
return false;
}
LOG(DEBUG) << "checking transaction " << lt << " of account " << account.addr.to_hex();
const StdSmcAddress& addr = account.addr;
block::gen::Transaction::Record trans;
@ -4388,7 +4413,8 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
}
}
if (is_first && is_masterchain() && account.is_special && account.tick &&
(tag != block::gen::TransactionDescr::trans_tick_tock || (td_cs.prefetch_ulong(4) & 1)) && account.orig_status == block::Account::acc_active) {
(tag != block::gen::TransactionDescr::trans_tick_tock || (td_cs.prefetch_ulong(4) & 1)) &&
account.orig_status == block::Account::acc_active) {
return reject_query(PSTRING() << "transaction " << lt << " of account " << addr.to_hex()
<< " is the first transaction for this special tick account in this block, but the "
"transaction is not a tick transaction");
@ -4417,6 +4443,13 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
int trans_type = block::Transaction::tr_none;
switch (tag) {
case block::gen::TransactionDescr::trans_ord: {
if (!block_limit_status_->fits(block::ParamLimits::cl_medium)) {
return reject_query(PSTRING() << "cannod add ordinary transaction because hard block limits are exceeded: "
<< "gas_used=" << block_limit_status_->gas_used
<< "(limit=" << block_limits_->gas.hard() << "), "
<< "lt_delta=" << block_limit_status_->cur_lt - block_limits_->start_lt
<< "(limit=" << block_limits_->lt_delta.hard() << ")");
}
trans_type = block::Transaction::tr_ord;
if (in_msg_root.is_null()) {
return reject_query(PSTRING() << "ordinary transaction " << lt << " of account " << addr.to_hex()
@ -4554,7 +4587,8 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
return reject_query(PSTRING() << "cannot re-create action phase of transaction " << lt << " for smart contract "
<< addr.to_hex());
}
if (trs->bounce_enabled && !trs->compute_phase->success && !trs->prepare_bounce_phase(action_phase_cfg_)) {
if (trs->bounce_enabled && (!trs->compute_phase->success || trs->action_phase->state_size_too_big) &&
!trs->prepare_bounce_phase(action_phase_cfg_)) {
return reject_query(PSTRING() << "cannot re-create bounce phase of transaction " << lt << " for smart contract "
<< addr.to_hex());
}
@ -4562,7 +4596,7 @@ bool ValidateQuery::check_one_transaction(block::Account& account, ton::LogicalT
return reject_query(PSTRING() << "cannot re-create the serialization of transaction " << lt
<< " for smart contract " << addr.to_hex());
}
if (block_limit_status_ && !trs->update_limits(*block_limit_status_)) {
if (!trs->update_limits(*block_limit_status_, false)) {
return fatal_error(PSTRING() << "cannot update block limit status to include transaction " << lt << " of account "
<< addr.to_hex());
}
@ -5037,7 +5071,7 @@ bool ValidateQuery::check_config_update(Ref<vm::CellSlice> old_conf_params, Ref<
return reject_query("no important parameters have been changed, but the block is marked as a key block");
}
vm::Dictionary dict1{ocfg_root, 32};
auto param0 = dict1.lookup_ref(td::BitArray<32>{(long long) 0});
auto param0 = dict1.lookup_ref(td::BitArray<32>{(long long)0});
if (param0.is_null()) {
if (cfg_acc_changed) {
return reject_query("new state of old configuration smart contract "s + old_cfg_addr.to_hex() +

View file

@ -371,6 +371,14 @@ class ValidateQuery : public td::actor::Actor {
bool check_mc_block_extra();
Ref<vm::Cell> get_virt_state_root(td::Bits256 block_root_hash);
bool check_timeout() {
if (timeout && timeout.is_in_past()) {
abort_query(td::Status::Error(ErrorCode::timeout, "timeout"));
return false;
}
return true;
}
};
} // namespace validator

View file

@ -87,6 +87,7 @@ class MasterchainState : virtual public ShardState {
virtual td::Status prepare() {
return td::Status::OK();
}
virtual block::SizeLimitsConfig::ExtMsgLimits get_ext_msg_limits() const = 0;
};
} // namespace validator

View file

@ -160,7 +160,8 @@ 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 update_shard_client_block_handle(BlockHandle handle, td::Ref<MasterchainState> state,
td::Promise<td::Unit> promise) = 0;
virtual void truncate(BlockSeqno seqno, ConstBlockHandle handle, td::Promise<td::Unit> promise) = 0;

View file

@ -260,7 +260,10 @@ void ValidatorManagerImpl::get_key_block_proof_link(BlockIdExt block_id, td::Pro
}
void ValidatorManagerImpl::new_external_message(td::BufferSlice data) {
auto R = create_ext_message(std::move(data));
if (last_masterchain_state_.is_null()) {
return;
}
auto R = create_ext_message(std::move(data), last_masterchain_state_->get_ext_msg_limits());
if (R.is_ok()) {
ext_messages_.emplace_back(R.move_as_ok());
}
@ -872,6 +875,11 @@ void ValidatorManagerImpl::get_top_masterchain_state_block(
std::pair<td::Ref<MasterchainState>, BlockIdExt>{last_masterchain_state_, last_masterchain_block_id_});
}
void ValidatorManagerImpl::get_last_liteserver_state_block(
td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) {
return get_top_masterchain_state_block(std::move(promise));
}
void ValidatorManagerImpl::send_get_block_request(BlockIdExt id, td::uint32 priority,
td::Promise<ReceivedBlock> promise) {
UNREACHABLE();

View file

@ -124,7 +124,7 @@ class ValidatorManagerImpl : public ValidatorManager {
//void get_block_description(BlockIdExt block_id, td::Promise<BlockDescription> promise) override;
void new_external_message(td::BufferSlice data) override;
void check_external_message(td::BufferSlice data, td::Promise<td::Unit> promise) override {
void check_external_message(td::BufferSlice data, td::Promise<td::Ref<ExtMessage>> promise) override {
UNREACHABLE();
}
void new_ihr_message(td::BufferSlice data) override;
@ -228,6 +228,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_top_masterchain_state(td::Promise<td::Ref<MasterchainState>> promise) override;
void get_top_masterchain_block(td::Promise<BlockIdExt> promise) override;
void get_top_masterchain_state_block(td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) override;
void get_last_liteserver_state_block(td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) override;
void send_get_block_request(BlockIdExt id, td::uint32 priority, td::Promise<ReceivedBlock> promise) override;
void send_get_zero_state_request(BlockIdExt id, td::uint32 priority, td::Promise<td::BufferSlice> promise) override;
@ -359,7 +360,8 @@ 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 update_shard_client_block_handle(BlockHandle handle, td::Ref<MasterchainState> state,
td::Promise<td::Unit> promise) override {
}
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override {

View file

@ -151,7 +151,7 @@ void ValidatorManagerImpl::get_key_block_proof_link(BlockIdExt block_id, td::Pro
}
void ValidatorManagerImpl::new_external_message(td::BufferSlice data) {
auto R = create_ext_message(std::move(data));
auto R = create_ext_message(std::move(data), block::SizeLimitsConfig::ExtMsgLimits());
if (R.is_ok()) {
ext_messages_.emplace_back(R.move_as_ok());
}

View file

@ -144,7 +144,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_key_block_proof_link(BlockIdExt block_id, td::Promise<td::BufferSlice> promise) override;
void new_external_message(td::BufferSlice data) override;
void check_external_message(td::BufferSlice data, td::Promise<td::Unit> promise) override {
void check_external_message(td::BufferSlice data, td::Promise<td::Ref<ExtMessage>> promise) override {
UNREACHABLE();
}
void new_ihr_message(td::BufferSlice data) override;
@ -284,6 +284,9 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_top_masterchain_state_block(td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) override {
UNREACHABLE();
}
void get_last_liteserver_state_block(td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) override {
UNREACHABLE();
}
void send_get_block_request(BlockIdExt id, td::uint32 priority, td::Promise<ReceivedBlock> promise) override {
UNREACHABLE();
@ -419,7 +422,8 @@ 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 update_shard_client_block_handle(BlockHandle handle, td::Ref<MasterchainState> state,
td::Promise<td::Unit> promise) override {
}
void prepare_stats(td::Promise<std::vector<std::pair<std::string, std::string>>> promise) override {

View file

@ -354,7 +354,8 @@ void ValidatorManagerMasterchainStarter::got_init_block_handle(BlockHandle handl
void ValidatorManagerMasterchainStarter::got_init_block_state(td::Ref<MasterchainState> state) {
state_ = std::move(state);
CHECK(state_->get_block_id() == opts_->init_block_id() || state_->ancestor_is_valid(opts_->init_block_id()));
CHECK(state_->get_block_id() == opts_->init_block_id() || state_->ancestor_is_valid(opts_->init_block_id()) ||
state_->get_block_id().seqno() < opts_->get_last_fork_masterchain_seqno());
//finish();
auto P = td::PromiseCreator::lambda(

View file

@ -376,12 +376,16 @@ void ValidatorManagerImpl::new_external_message(td::BufferSlice data) {
if (!is_collator()) {
return;
}
if (last_masterchain_state_.is_null()) {
VLOG(VALIDATOR_NOTICE) << "dropping ext message: validator is not ready";
return;
}
if ((double)ext_messages_.size() > max_mempool_num()) {
return;
}
auto R = create_ext_message(std::move(data));
auto R = create_ext_message(std::move(data), last_masterchain_state_->get_ext_msg_limits());
if (R.is_error()) {
VLOG(VALIDATOR_NOTICE) << "dropping bad external message: " << R.move_as_error();
VLOG(VALIDATOR_NOTICE) << "dropping bad ext message: " << R.move_as_error();
return;
}
add_external_message(R.move_as_ok());
@ -400,8 +404,14 @@ void ValidatorManagerImpl::add_external_message(td::Ref<ExtMessage> msg) {
}
}
}
void ValidatorManagerImpl::check_external_message(td::BufferSlice data, td::Promise<td::Unit> promise) {
run_check_external_message(std::move(data), actor_id(this), std::move(promise));
void ValidatorManagerImpl::check_external_message(td::BufferSlice data, td::Promise<td::Ref<ExtMessage>> promise) {
auto state = do_get_last_liteserver_state();
if (state.is_null()) {
promise.set_error(td::Status::Error(ErrorCode::notready, "not ready"));
return;
}
run_check_external_message(std::move(data), state->get_ext_msg_limits(), actor_id(this),
std::move(promise));
}
void ValidatorManagerImpl::new_ihr_message(td::BufferSlice data) {
@ -1397,6 +1407,16 @@ void ValidatorManagerImpl::get_top_masterchain_state(td::Promise<td::Ref<Masterc
}
}
td::Ref<MasterchainState> ValidatorManagerImpl::do_get_last_liteserver_state() {
if (last_masterchain_state_.is_null()) {
return {};
}
if (last_liteserver_state_.is_null() || last_liteserver_state_->get_unix_time() < td::Clocks::system() - 30) {
last_liteserver_state_ = last_masterchain_state_;
}
return last_liteserver_state_;
}
void ValidatorManagerImpl::get_top_masterchain_block(td::Promise<BlockIdExt> promise) {
if (!last_masterchain_block_id_.is_valid()) {
promise.set_error(td::Status::Error(ton::ErrorCode::notready, "not started"));
@ -1415,6 +1435,16 @@ void ValidatorManagerImpl::get_top_masterchain_state_block(
}
}
void ValidatorManagerImpl::get_last_liteserver_state_block(
td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) {
auto state = do_get_last_liteserver_state();
if (state.is_null()) {
promise.set_error(td::Status::Error(ton::ErrorCode::notready, "not started"));
} else {
promise.set_result(std::pair<td::Ref<MasterchainState>, BlockIdExt>{state, state->get_block_id()});
}
}
void ValidatorManagerImpl::send_get_block_request(BlockIdExt id, td::uint32 priority,
td::Promise<ReceivedBlock> promise) {
callback_->download_block(id, priority, td::Timestamp::in(10.0), std::move(promise));
@ -2369,9 +2399,13 @@ 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) {
void ValidatorManagerImpl::update_shard_client_block_handle(BlockHandle handle, td::Ref<MasterchainState> state,
td::Promise<td::Unit> promise) {
shard_client_handle_ = std::move(handle);
auto seqno = shard_client_handle_->id().seqno();
if (last_liteserver_state_.is_null() || last_liteserver_state_->get_block_id().seqno() < seqno) {
last_liteserver_state_ = std::move(state);
}
shard_client_update(seqno);
promise.set_value(td::Unit());
}

View file

@ -255,6 +255,9 @@ class ValidatorManagerImpl : public ValidatorManager {
BlockHandle last_key_block_handle_;
BlockHandle last_known_key_block_handle_;
BlockHandle shard_client_handle_;
td::Ref<MasterchainState> last_liteserver_state_;
td::Ref<MasterchainState> do_get_last_liteserver_state();
BlockHandle gc_masterchain_handle_;
td::Ref<MasterchainState> gc_masterchain_state_;
@ -279,7 +282,8 @@ 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;
void update_shard_client_block_handle(BlockHandle handle, td::Ref<MasterchainState> state,
td::Promise<td::Unit> promise) override;
bool out_of_sync();
void applied_hardfork();
@ -344,7 +348,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void new_external_message(td::BufferSlice data) override;
void add_external_message(td::Ref<ExtMessage> message);
void check_external_message(td::BufferSlice data, td::Promise<td::Unit> promise) override;
void check_external_message(td::BufferSlice data, td::Promise<td::Ref<ExtMessage>> promise) override;
void new_ihr_message(td::BufferSlice data) override;
void new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override;
@ -442,6 +446,7 @@ class ValidatorManagerImpl : public ValidatorManager {
void get_top_masterchain_state(td::Promise<td::Ref<MasterchainState>> promise) override;
void get_top_masterchain_block(td::Promise<BlockIdExt> promise) override;
void get_top_masterchain_state_block(td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) override;
void get_last_liteserver_state_block(td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) override;
void send_get_block_request(BlockIdExt id, td::uint32 priority, td::Promise<ReceivedBlock> promise) override;
void send_get_zero_state_request(BlockIdExt id, td::uint32 priority, td::Promise<td::BufferSlice> promise) override;

View file

@ -107,9 +107,6 @@ void ShardClient::start_up_init_mode() {
void ShardClient::applied_all_shards() {
LOG(DEBUG) << "shardclient: " << masterchain_block_handle_->id() << " finished";
masterchain_state_.clear();
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &ShardClient::saved_to_db);
@ -121,7 +118,8 @@ void ShardClient::applied_all_shards() {
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) {});
std::move(masterchain_state_), [](td::Unit) {});
masterchain_state_.clear();
if (promise_) {
promise_.set_value(td::Unit());
}

View file

@ -81,13 +81,22 @@ void AsyncStateSerializer::alarm() {
}
void AsyncStateSerializer::request_masterchain_state() {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), manager = manager_](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::got_masterchain_state,
td::Ref<MasterchainState>(R.move_as_ok()));
td::actor::send_closure(manager, &ValidatorManager::get_cell_db_reader,
[SelfId, state = td::Ref<MasterchainState>(R.move_as_ok())](
td::Result<std::shared_ptr<vm::CellDbReader>> R) mutable {
if (R.is_error()) {
td::actor::send_closure(SelfId, &AsyncStateSerializer::fail_handler,
R.move_as_error_prefix("failed to get cell db reader: "));
} else {
td::actor::send_closure(SelfId, &AsyncStateSerializer::got_masterchain_state,
std::move(state), R.move_as_ok());
}
});
}
});
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, masterchain_handle_, std::move(P));
@ -136,26 +145,13 @@ void AsyncStateSerializer::next_iteration() {
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, masterchain_handle_, std::move(P));
return;
}
if (!cell_db_reader_) {
running_ = true;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<std::shared_ptr<vm::CellDbReader>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &AsyncStateSerializer::fail_handler,
R.move_as_error_prefix("failed to get cell db reader: "));
} else {
td::actor::send_closure(SelfId, &AsyncStateSerializer::got_cell_db_reader, R.move_as_ok());
}
});
td::actor::send_closure(manager_, &ValidatorManager::get_cell_db_reader, std::move(P));
return;
}
if (!have_masterchain_state_) {
LOG(INFO) << "started serializing persistent state for " << masterchain_handle_->id().id;
// block next attempts immediately, but send actual request later
running_ = true;
delay_action(
[SelfId = actor_id(this)]() { td::actor::send_closure(SelfId, &AsyncStateSerializer::request_masterchain_state); },
td::Timestamp::in(td::Random::fast(0, 3600)));
delay_action([SelfId = actor_id(
this)]() { td::actor::send_closure(SelfId, &AsyncStateSerializer::request_masterchain_state); },
td::Timestamp::in(td::Random::fast(0, 3600)));
return;
}
while (next_idx_ < shards_.size()) {
@ -169,7 +165,6 @@ void AsyncStateSerializer::next_iteration() {
LOG(INFO) << "finished serializing persistent state for " << masterchain_handle_->id().id;
last_key_block_ts_ = masterchain_handle_->unix_time();
last_key_block_id_ = masterchain_handle_->id();
cell_db_reader_ = nullptr;
}
if (!saved_to_db_) {
running_ = true;
@ -218,13 +213,6 @@ void AsyncStateSerializer::store_persistent_state_description(td::Ref<Masterchai
next_iteration();
}
void AsyncStateSerializer::got_cell_db_reader(std::shared_ptr<vm::CellDbReader> cell_db_reader) {
cell_db_reader_ = std::move(cell_db_reader);
running_ = false;
attempt_ = 0;
next_iteration();
}
void AsyncStateSerializer::got_masterchain_handle(BlockHandle handle) {
CHECK(!masterchain_handle_);
masterchain_handle_ = std::move(handle);
@ -233,7 +221,8 @@ void AsyncStateSerializer::got_masterchain_handle(BlockHandle handle) {
next_iteration();
}
void AsyncStateSerializer::got_masterchain_state(td::Ref<MasterchainState> state) {
void AsyncStateSerializer::got_masterchain_state(td::Ref<MasterchainState> state,
std::shared_ptr<vm::CellDbReader> cell_db_reader) {
LOG(INFO) << "serializing masterchain state " << masterchain_handle_->id().id;
have_masterchain_state_ = true;
CHECK(next_idx_ == 0);
@ -246,7 +235,7 @@ void AsyncStateSerializer::got_masterchain_state(td::Ref<MasterchainState> state
}
}
auto write_data = [hash = state->root_cell()->get_hash(), cell_db_reader = cell_db_reader_] (td::FileFd& fd) {
auto write_data = [hash = state->root_cell()->get_hash(), cell_db_reader](td::FileFd& fd) {
return vm::std_boc_serialize_to_file_large(cell_db_reader, hash, fd, 31);
};
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
@ -265,20 +254,32 @@ void AsyncStateSerializer::stored_masterchain_state() {
}
void AsyncStateSerializer::got_shard_handle(BlockHandle handle) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &AsyncStateSerializer::fail_handler, R.move_as_error());
} else {
td::actor::send_closure(SelfId, &AsyncStateSerializer::got_shard_state, handle, R.move_as_ok());
}
});
auto P = td::PromiseCreator::lambda(
[SelfId = actor_id(this), handle, manager = manager_](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &AsyncStateSerializer::fail_handler, R.move_as_error());
} else {
td::actor::send_closure(
manager, &ValidatorManager::get_cell_db_reader,
[SelfId, state = R.move_as_ok(), handle](td::Result<std::shared_ptr<vm::CellDbReader>> R) mutable {
if (R.is_error()) {
td::actor::send_closure(SelfId, &AsyncStateSerializer::fail_handler,
R.move_as_error_prefix("failed to get cell db reader: "));
} else {
td::actor::send_closure(SelfId, &AsyncStateSerializer::got_shard_state, handle, std::move(state),
R.move_as_ok());
}
});
}
});
td::actor::send_closure(manager_, &ValidatorManager::get_shard_state_from_db, handle, std::move(P));
}
void AsyncStateSerializer::got_shard_state(BlockHandle handle, td::Ref<ShardState> state) {
void AsyncStateSerializer::got_shard_state(BlockHandle handle, td::Ref<ShardState> state,
std::shared_ptr<vm::CellDbReader> cell_db_reader) {
LOG(INFO) << "serializing shard state " << handle->id().id;
auto write_data = [hash = state->root_cell()->get_hash(), cell_db_reader = cell_db_reader_] (td::FileFd& fd) {
auto write_data = [hash = state->root_cell()->get_hash(), cell_db_reader](td::FileFd& fd) {
return vm::std_boc_serialize_to_file_large(cell_db_reader, hash, fd, 31);
};
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle](td::Result<td::Unit> R) {

View file

@ -42,7 +42,6 @@ class AsyncStateSerializer : public td::actor::Actor {
td::uint32 next_idx_ = 0;
std::shared_ptr<vm::CellDbReader> cell_db_reader_ = nullptr;
BlockHandle masterchain_handle_;
bool stored_persistent_state_description_ = false;
bool have_masterchain_state_ = false;
@ -72,12 +71,11 @@ 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_cell_db_reader(std::shared_ptr<vm::CellDbReader> cell_db_reader);
void got_masterchain_handle(BlockHandle handle_);
void got_masterchain_state(td::Ref<MasterchainState> state);
void got_masterchain_state(td::Ref<MasterchainState> state, std::shared_ptr<vm::CellDbReader> cell_db_reader);
void stored_masterchain_state();
void got_shard_handle(BlockHandle handle);
void got_shard_state(BlockHandle handle, td::Ref<ShardState> state);
void got_shard_state(BlockHandle handle, td::Ref<ShardState> state, std::shared_ptr<vm::CellDbReader> cell_db_reader);
void get_masterchain_seqno(td::Promise<BlockSeqno> promise) {
promise.set_result(last_block_id_.id.seqno);

View file

@ -36,13 +36,45 @@ void ValidatorGroup::generate_block_candidate(td::uint32 round_id, td::Promise<B
promise.set_error(td::Status::Error(ErrorCode::notready, "cannot collate block: group not started"));
return;
}
if (cached_collated_block_) {
if (cached_collated_block_->result) {
promise.set_result(cached_collated_block_->result.value().clone());
} else {
cached_collated_block_->promises.push_back(std::move(promise));
}
return;
}
cached_collated_block_ = std::make_shared<CachedCollatedBlock>();
cached_collated_block_->promises.push_back(std::move(promise));
td::Promise<BlockCandidate> P = [SelfId = actor_id(this),
cache = cached_collated_block_](td::Result<BlockCandidate> R) {
td::actor::send_closure(SelfId, &ValidatorGroup::generated_block_candidate, std::move(cache), std::move(R));
};
if (lite_mode_) {
send_collate_query(round_id, td::Timestamp::in(10.0), std::move(promise));
send_collate_query(round_id, td::Timestamp::in(10.0), std::move(P));
return;
}
run_collate_query(shard_, min_masterchain_block_id_, prev_block_ids_,
Ed25519_PublicKey{local_id_full_.ed25519_value().raw()}, validator_set_, manager_,
td::Timestamp::in(20.0), std::move(promise));
td::Timestamp::in(10.0), std::move(P));
}
void ValidatorGroup::generated_block_candidate(std::shared_ptr<CachedCollatedBlock> cache,
td::Result<BlockCandidate> R) {
if (R.is_error()) {
for (auto &p : cache->promises) {
p.set_error(R.error().clone());
}
if (cache == cached_collated_block_) {
cached_collated_block_ = nullptr;
}
} else {
cache->result = R.move_as_ok();
for (auto &p : cache->promises) {
p.set_value(cache->result.value().clone());
}
}
cache->promises.clear();
}
void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidate block,
@ -101,18 +133,12 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
return;
}
VLOG(VALIDATOR_DEBUG) << "validating block candidate " << next_block_id;
block.id = next_block_id;
run_validate_query(shard_, min_masterchain_block_id_, prev_block_ids_, std::move(block), validator_set_, manager_,
td::Timestamp::in(10.0), std::move(P),
td::Timestamp::in(15.0), std::move(P),
collator_config_.full_collated_data ? ValidateMode::full_collated_data : 0);
}
void ValidatorGroup::update_approve_cache(td::uint32 round_id, CacheKey key, UnixTime value) {
if (approved_candidates_cache_round_ != round_id) {
return;
}
approved_candidates_cache_[key] = value;
}
void ValidatorGroup::accept_block_candidate(td::uint32 round_id, PublicKeyHash src, td::BufferSlice block_data,
RootHash root_hash, FileHash file_hash,
std::vector<BlockSignature> signatures,
@ -139,6 +165,7 @@ void ValidatorGroup::accept_block_candidate(td::uint32 round_id, PublicKeyHash s
accept_block_query(next_block_id, std::move(block), std::move(prev_block_ids_), std::move(sig_set),
std::move(approve_sig_set), src == local_id_, std::move(promise));
prev_block_ids_ = std::vector<BlockIdExt>{next_block_id};
cached_collated_block_ = nullptr;
}
void ValidatorGroup::accept_block_query(BlockIdExt block_id, td::Ref<BlockData> block, std::vector<BlockIdExt> prev,
@ -306,6 +333,7 @@ void ValidatorGroup::create_session() {
void ValidatorGroup::start(std::vector<BlockIdExt> prev, BlockIdExt min_masterchain_block_id) {
prev_block_ids_ = prev;
min_masterchain_block_id_ = min_masterchain_block_id;
cached_collated_block_ = nullptr;
started_ = true;
if (init_) {

View file

@ -128,6 +128,14 @@ class ValidatorGroup : public td::actor::Actor {
bool lite_mode_ = false;
td::uint32 last_known_round_id_ = 0;
struct CachedCollatedBlock {
td::optional<BlockCandidate> result;
std::vector<td::Promise<BlockCandidate>> promises;
};
std::shared_ptr<CachedCollatedBlock> cached_collated_block_;
void generated_block_candidate(std::shared_ptr<CachedCollatedBlock> cache, td::Result<BlockCandidate> R);
typedef std::tuple<td::Bits256, BlockIdExt, FileHash, FileHash> CacheKey;
std::map<CacheKey, UnixTime> approved_candidates_cache_;
td::uint32 approved_candidates_cache_round_ = 0;

View file

@ -36,6 +36,7 @@
#include "interfaces/shard.h"
#include "catchain/catchain-types.h"
#include "interfaces/out-msg-queue-proof.h"
#include "interfaces/external-message.h"
namespace ton {
@ -166,6 +167,8 @@ class ValidatorManagerInterface : public td::actor::Actor {
virtual void get_top_masterchain_block(td::Promise<BlockIdExt> promise) = 0;
virtual void get_top_masterchain_state_block(
td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) = 0;
virtual void get_last_liteserver_state_block(
td::Promise<std::pair<td::Ref<MasterchainState>, BlockIdExt>> promise) = 0;
virtual void get_block_data(BlockHandle handle, td::Promise<td::BufferSlice> promise) = 0;
virtual void check_zero_state_exists(BlockIdExt block_id, td::Promise<bool> promise) = 0;
@ -187,7 +190,7 @@ class ValidatorManagerInterface : public td::actor::Actor {
virtual void write_handle(BlockHandle handle, td::Promise<td::Unit> promise) = 0;
virtual void new_external_message(td::BufferSlice data) = 0;
virtual void check_external_message(td::BufferSlice data, td::Promise<td::Unit> promise) = 0;
virtual void check_external_message(td::BufferSlice data, td::Promise<td::Ref<ExtMessage>> promise) = 0;
virtual void new_ihr_message(td::BufferSlice data) = 0;
virtual void new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) = 0;