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

Add checks for external messages

This commit is contained in:
OmicronTau 2021-11-13 23:28:06 +03:00 committed by EmelyanenkoK
parent 69d0472510
commit 3384d204d2
11 changed files with 396 additions and 119 deletions

View file

@ -46,6 +46,8 @@ td::Result<std::vector<td::Ref<ShardTopBlockDescription>>> create_new_shard_bloc
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_accept_block_query(BlockIdExt id, td::Ref<BlockData> data, std::vector<BlockIdExt> prev,
td::Ref<ValidatorSet> validator_set, td::Ref<BlockSignatureSet> signatures,
td::Ref<BlockSignatureSet> approve_signatures, bool send_broadcast,
@ -81,6 +83,8 @@ void run_collate_hardfork(ShardIdFull shard, const BlockIdExt& min_masterchain_b
td::Promise<BlockCandidate> promise);
void run_liteserver_query(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager,
td::actor::ActorId<LiteServerCache> cache, td::Promise<td::BufferSlice> promise);
void run_fetch_account_state(WorkchainId wc, StdSmcAddress addr, td::actor::ActorId<ValidatorManager> manager,
td::Promise<std::tuple<td::Ref<vm::CellSlice>,UnixTime,LogicalTime,std::unique_ptr<block::ConfigInfo>>> promise);
void run_validate_shard_block_description(td::BufferSlice data, BlockHandle masterchain_block,
td::Ref<MasterchainState> masterchain_state,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,

View file

@ -103,6 +103,27 @@ class Collator final : public td::actor::Actor {
return 2;
}
static td::Result<std::unique_ptr<block::ConfigInfo>>
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);
static td::Result<std::unique_ptr<block::Transaction>>
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);
private:
void start_up() override;
void alarm() override;

View file

@ -1556,68 +1556,92 @@ bool Collator::init_lt() {
}
bool Collator::fetch_config_params() {
old_mparams_ = config_->get_config_param(9);
{
auto res = config_->get_storage_prices();
if (res.is_error()) {
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());
}
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) {
*old_mparams = config->get_config_param(9);
{
auto res = config->get_storage_prices();
if (res.is_error()) {
return res.move_as_error();
}
storage_prices_ = res.move_as_ok();
*storage_prices = res.move_as_ok();
}
{
// generate rand seed
prng::rand_gen().strong_rand_bytes(rand_seed_.data(), 32);
LOG(DEBUG) << "block random seed set to " << rand_seed_.to_hex();
prng::rand_gen().strong_rand_bytes(rand_seed->data(), 32);
LOG(DEBUG) << "block random seed set to " << rand_seed->to_hex();
}
{
// compute compute_phase_cfg / storage_phase_cfg
auto cell = config_->get_config_param(is_masterchain() ? 20 : 21);
auto cell = config->get_config_param(wc == ton::masterchainId ? 20 : 21);
if (cell.is_null()) {
return fatal_error("cannot fetch current gas prices and limits from masterchain configuration");
return td::Status::Error(-668, "cannot fetch 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");
if (!compute_phase_cfg->parse_GasLimitsPrices(std::move(cell), storage_phase_cfg->freeze_due_limit,
storage_phase_cfg->delete_due_limit)) {
return td::Status::Error(-668, "cannot unpack current gas prices and limits from masterchain configuration");
}
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();
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();
}
{
// compute action_phase_cfg
block::gen::MsgForwardPrices::Record rec;
auto cell = config_->get_config_param(24);
auto cell = config->get_config_param(24);
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
return fatal_error("cannot fetch masterchain message transfer prices from masterchain configuration");
return td::Status::Error(-668, "cannot fetch masterchain message transfer prices from masterchain configuration");
}
action_phase_cfg_.fwd_mc =
action_phase_cfg->fwd_mc =
block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor,
(unsigned)rec.first_frac, (unsigned)rec.next_frac};
cell = config_->get_config_param(25);
cell = config->get_config_param(25);
if (cell.is_null() || !tlb::unpack_cell(std::move(cell), rec)) {
return fatal_error("cannot fetch standard message transfer prices from masterchain configuration");
return td::Status::Error(-668, "cannot fetch standard message transfer prices from masterchain configuration");
}
action_phase_cfg_.fwd_std =
action_phase_cfg->fwd_std =
block::MsgPrices{rec.lump_price, rec.bit_price, rec.cell_price, rec.ihr_price_factor,
(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->workchains = &config->get_workchain_list();
action_phase_cfg->bounce_msg_body = (config->has_capability(ton::capBounceMsgBody) ? 256 : 0);
}
{
// fetch block_grams_created
auto cell = config_->get_config_param(14);
auto cell = config->get_config_param(14);
if (cell.is_null()) {
basechain_create_fee_ = masterchain_create_fee_ = td::zero_refint();
*basechain_create_fee = *masterchain_create_fee = td::zero_refint();
} else {
block::gen::BlockCreateFees::Record create_fees;
if (!(tlb::unpack_cell(cell, create_fees) &&
block::tlb::t_Grams.as_integer_to(create_fees.masterchain_block_fee, masterchain_create_fee_) &&
block::tlb::t_Grams.as_integer_to(create_fees.basechain_block_fee, basechain_create_fee_))) {
return fatal_error("cannot unpack BlockCreateFees from configuration parameter #14");
block::tlb::t_Grams.as_integer_to(create_fees.masterchain_block_fee, *masterchain_create_fee) &&
block::tlb::t_Grams.as_integer_to(create_fees.basechain_block_fee, *basechain_create_fee))) {
return td::Status::Error(-668, "cannot unpack BlockCreateFees from configuration parameter #14");
}
}
}
return true;
return std::move(config);
}
bool Collator::compute_minted_amount(block::CurrencyCollection& to_mint) {
@ -2218,75 +2242,25 @@ Ref<vm::Cell> Collator::create_ordinary_transaction(Ref<vm::Cell> msg_root) {
}
block::Account* acc = acc_res.move_as_ok();
assert(acc);
if (acc->last_trans_end_lt_ >= start_lt && acc->transactions.empty()) {
fatal_error(PSTRING() << "last transaction time in the state of account " << workchain() << ":" << addr.to_hex()
<< " is too large");
return {};
}
auto trans_min_lt = start_lt;
if (external) {
// transactions processing external messages must have lt larger than all processed internal messages
trans_min_lt = std::max(trans_min_lt, last_proc_int_msg_.first);
}
std::unique_ptr<block::Transaction> trans =
std::make_unique<block::Transaction>(*acc, block::Transaction::tr_ord, trans_min_lt + 1, now_, msg_root);
bool ihr_delivered = false; // FIXME
if (!trans->unpack_input_msg(ihr_delivered, &action_phase_cfg_)) {
if (external) {
// inbound external message was not accepted
LOG(DEBUG) << "inbound external message rejected by account " << addr.to_hex()
<< " before smart-contract execution";
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) {
// ignorable errors
LOG(DEBUG) << error.message();
return {};
}
fatal_error("cannot unpack input message for a new transaction");
return {};
}
if (trans->bounce_enabled) {
if (!trans->prepare_storage_phase(storage_phase_cfg_, true)) {
fatal_error("cannot create storage phase of a new transaction for smart contract "s + addr.to_hex());
return {};
}
if (!external && !trans->prepare_credit_phase()) {
fatal_error("cannot create credit phase of a new transaction for smart contract "s + addr.to_hex());
return {};
}
} else {
if (!external && !trans->prepare_credit_phase()) {
fatal_error("cannot create credit phase of a new transaction for smart contract "s + addr.to_hex());
return {};
}
if (!trans->prepare_storage_phase(storage_phase_cfg_, true, true)) {
fatal_error("cannot create storage phase of a new transaction for smart contract "s + addr.to_hex());
return {};
}
}
if (!trans->prepare_compute_phase(compute_phase_cfg_)) {
fatal_error("cannot create compute phase of a new transaction for smart contract "s + addr.to_hex());
return {};
}
if (!trans->compute_phase->accepted) {
if (external) {
// inbound external message was not accepted
LOG(DEBUG) << "inbound external message rejected by transaction " << addr.to_hex();
return {};
} else if (trans->compute_phase->skip_reason == block::ComputePhase::sk_none) {
fatal_error("new ordinary transaction for smart contract "s + addr.to_hex() +
" has not been accepted by the smart contract (?)");
return {};
}
}
if (trans->compute_phase->success && !trans->prepare_action_phase(action_phase_cfg_)) {
fatal_error("cannot create action phase of a new transaction for smart contract "s + addr.to_hex());
return {};
}
if (trans->bounce_enabled && !trans->compute_phase->success && !trans->prepare_bounce_phase(action_phase_cfg_)) {
fatal_error("cannot create bounce phase of a new transaction for smart contract "s + addr.to_hex());
return {};
}
if (!trans->serialize()) {
fatal_error("cannot serialize new transaction for smart contract "s + addr.to_hex());
fatal_error(std::move(error));
return {};
}
std::unique_ptr<block::Transaction> trans = res.move_as_ok();
if (!trans->update_limits(*block_limit_status_)) {
fatal_error("cannot update block limit status to include the new transaction");
return {};
@ -2296,6 +2270,7 @@ Ref<vm::Cell> Collator::create_ordinary_transaction(Ref<vm::Cell> msg_root) {
fatal_error("cannot commit new transaction for smart contract "s + addr.to_hex());
return {};
}
register_new_msgs(*trans);
update_max_lt(acc->last_trans_end_lt_);
// temporary patch to stop producing dangerous block
@ -2305,6 +2280,75 @@ Ref<vm::Cell> Collator::create_ordinary_transaction(Ref<vm::Cell> msg_root) {
return trans_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) {
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");
}
auto trans_min_lt = lt;
if (external) {
// transactions processing external messages must have lt larger than all processed internal messages
trans_min_lt = std::max(trans_min_lt, after_lt);
}
std::unique_ptr<block::Transaction> trans =
std::make_unique<block::Transaction>(*acc, block::Transaction::tr_ord, trans_min_lt + 1, utime, msg_root);
bool ihr_delivered = false; // FIXME
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");
}
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());
}
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());
}
} 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());
}
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());
}
}
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());
}
if (!trans->compute_phase->accepted) {
if (external) {
// inbound external message was not accepted
return td::Status::Error(-701,"inbound external message rejected by transaction "s + acc->addr.to_hex());
} 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());
}
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->serialize()) {
return td::Status::Error(-669,"cannot serialize new transaction for smart contract "s + acc->addr.to_hex());
}
return std::move(trans);
}
void Collator::update_max_lt(ton::LogicalTime lt) {
CHECK(lt >= start_lt);
if (lt > max_lt) {

View file

@ -16,19 +16,25 @@
Copyright 2017-2020 Telegram Systems LLP
*/
#include "external-message.hpp"
#include "collator-impl.h"
#include "vm/boc.h"
#include "block/block-parse.h"
#include "block/block-auto.h"
#include "block/block-db.h"
#include "fabric.h"
#include "td/actor/actor.h"
#include "td/utils/Random.h"
#include "crypto/openssl/rand.hpp"
namespace ton {
namespace validator {
using td::Ref;
ExtMessageQ::ExtMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, AccountIdPrefixFull addr_prefix)
: root_(std::move(root)), addr_prefix_(addr_prefix), data_(std::move(data)) {
ExtMessageQ::ExtMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, AccountIdPrefixFull addr_prefix, ton::WorkchainId wc, ton::StdSmcAddress addr)
: root_(std::move(root)), addr_prefix_(addr_prefix), data_(std::move(data)), wc_(wc), addr_(addr) {
hash_ = block::compute_file_hash(data_);
}
@ -70,7 +76,95 @@ td::Result<Ref<ExtMessageQ>> ExtMessageQ::create_ext_message(td::BufferSlice dat
if (!dest_prefix.is_valid()) {
return td::Status::Error("destination of an inbound external message is an invalid blockchain address");
}
return Ref<ExtMessageQ>{true, std::move(data), std::move(ext_msg), dest_prefix};
ton::StdSmcAddress addr;
ton::WorkchainId wc;
if(!block::tlb::t_MsgAddressInt.extract_std_address(info.dest, wc, addr)) {
return td::Status::Error(PSLICE() << "Can't parse destination address");
}
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));
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
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 {
if (res.is_error()) {
promise.set_error(td::Status::Error(PSLICE() << "Failed to get account state"));
} else {
auto tuple = res.move_as_ok();
block::Account acc;
auto shard_acc = std::move(std::get<0>(tuple));
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)) {
promise.set_error(td::Status::Error(PSLICE() << "Failed to unpack account state"));
} else {
if(run_message_on_account(wc, &acc, utime, lt + 1, msg_root, std::move(config))) {
promise.set_value(td::Unit());
} else {
promise.set_error(td::Status::Error(PSLICE() << "External message was not accepted"));
}
}
}
}
);
}
bool ExtMessageQ::run_message_on_account(ton::WorkchainId wc,
block::Account* acc,
UnixTime utime, LogicalTime lt,
td::Ref<vm::Cell> msg_root,
std::unique_ptr<block::ConfigInfo> config) {
Ref<vm::Cell> old_mparams;
std::vector<block::StoragePrices> storage_prices_;
block::StoragePhaseConfig storage_phase_cfg_{&storage_prices_};
td::BitArray<256> rand_seed_;
block::ComputePhaseConfig compute_phase_cfg_;
block::ActionPhaseConfig action_phase_cfg_;
td::RefInt256 masterchain_create_fee, basechain_create_fee;
auto fetch_res = Collator::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, wc);
if(fetch_res.is_error()) {
auto error = fetch_res.move_as_error();
LOG(DEBUG) << "Cannot fetch config params" << error.message();
return false;
}
auto res = Collator::impl_create_ordinary_transaction(msg_root, acc, utime, lt,
&storage_phase_cfg_, &compute_phase_cfg_,
&action_phase_cfg_,
true, lt);
if(res.is_error()) {
auto error = res.move_as_error();
LOG(DEBUG) << "Cannot run message on account" << error.message();
return false;
}
std::unique_ptr<block::Transaction> trans = res.move_as_ok();
auto trans_root = trans->commit(*acc);
if (trans_root.is_null()) {
LOG(DEBUG) << "cannot commit new transaction for smart contract ";
return false;
}
return true;
}
} // namespace validator

View file

@ -18,9 +18,11 @@
*/
#pragma once
#include "interfaces/validator-manager.h"
#include "validator/interfaces/external-message.h"
#include "auto/tl/ton_api.h"
#include "adnl/utils.hpp"
#include "block/transaction.h"
namespace ton {
@ -31,6 +33,8 @@ class ExtMessageQ : public ExtMessage {
AccountIdPrefixFull addr_prefix_;
td::BufferSlice data_;
Hash hash_;
ton::WorkchainId wc_;
ton::StdSmcAddress addr_;
public:
static constexpr unsigned max_ext_msg_size = 65535;
@ -47,8 +51,23 @@ class ExtMessageQ : public ExtMessage {
Hash hash() const override {
return hash_;
}
ExtMessageQ(td::BufferSlice data, td::Ref<vm::Cell> root, AccountIdPrefixFull shard);
ton::WorkchainId wc() const override {
return wc_;
}
ton::StdSmcAddress addr() const override {
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);
static bool run_message_on_account(ton::WorkchainId wc,
block::Account* acc,
UnixTime utime, LogicalTime lt,
td::Ref<vm::Cell> msg_root,
std::unique_ptr<block::ConfigInfo> config);
};
} // namespace validator

View file

@ -116,6 +116,10 @@ td::Result<td::Ref<ExtMessage>> create_ext_message(td::BufferSlice data) {
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));
}
td::Result<td::Ref<IhrMessage>> create_ihr_message(td::BufferSlice data) {
TRY_RESULT(res, IhrMessageQ::create_ihr_message(std::move(data)));
return std::move(res);
@ -237,6 +241,11 @@ void run_liteserver_query(td::BufferSlice data, td::actor::ActorId<ValidatorMana
LiteQuery::run_query(std::move(data), std::move(manager), std::move(promise));
}
void run_fetch_account_state(WorkchainId wc, StdSmcAddress addr, td::actor::ActorId<ValidatorManager> manager,
td::Promise<std::tuple<td::Ref<vm::CellSlice>,UnixTime,LogicalTime,std::unique_ptr<block::ConfigInfo>>> promise) {
LiteQuery::fetch_account_state(wc, addr, std::move(manager), std::move(promise));
}
void run_validate_shard_block_description(td::BufferSlice data, BlockHandle masterchain_block,
td::Ref<MasterchainState> masterchain_state,
td::actor::ActorId<ValidatorManager> manager, td::Timestamp timeout,

View file

@ -58,15 +58,28 @@ void LiteQuery::run_query(td::BufferSlice data, td::actor::ActorId<ValidatorMana
td::actor::create_actor<LiteQuery>("litequery", std::move(data), std::move(manager), std::move(promise)).release();
}
void LiteQuery::fetch_account_state(WorkchainId wc, StdSmcAddress acc_addr, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<std::tuple<td::Ref<vm::CellSlice>,UnixTime,LogicalTime,std::unique_ptr<block::ConfigInfo>>> promise) {
td::actor::create_actor<LiteQuery>("litequery", wc, acc_addr, std::move(manager), std::move(promise)).release();
}
LiteQuery::LiteQuery(td::BufferSlice data, td::actor::ActorId<ValidatorManager> manager,
td::Promise<td::BufferSlice> promise)
: query_(std::move(data)), manager_(std::move(manager)), promise_(std::move(promise)) {
timeout_ = td::Timestamp::in(default_timeout_msec * 0.001);
}
LiteQuery::LiteQuery(WorkchainId wc, StdSmcAddress acc_addr, td::actor::ActorId<ValidatorManager> manager,
td::Promise<std::tuple<td::Ref<vm::CellSlice>,UnixTime,LogicalTime,std::unique_ptr<block::ConfigInfo>>> promise)
: manager_(std::move(manager)), acc_state_promise_(std::move(promise)), acc_workchain_(wc), acc_addr_(acc_addr) {
timeout_ = td::Timestamp::in(default_timeout_msec * 0.001);
}
void LiteQuery::abort_query(td::Status reason) {
LOG(INFO) << "aborted liteserver query: " << reason.to_string();
if (promise_) {
if (acc_state_promise_) {
acc_state_promise_.set_error(std::move(reason));
} else if (promise_) {
promise_.set_error(std::move(reason));
}
stop();
@ -111,6 +124,11 @@ bool LiteQuery::finish_query(td::BufferSlice result) {
void LiteQuery::start_up() {
alarm_timestamp() = timeout_;
if(acc_state_promise_) {
td::actor::send_closure_later(actor_id(this),&LiteQuery::perform_fetchAccountState);
return;
}
auto F = fetch_tl_object<ton::lite_api::Function>(std::move(query_), true);
if (F.is_error()) {
abort_query(F.move_as_error());
@ -205,17 +223,23 @@ 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), 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());
} else {
auto pair = res.move_as_ok();
td::actor::send_closure_later(Self, &LiteQuery::continue_getMasterchainInfo, std::move(pair.first),
auto func = return_state ? &LiteQuery::gotMasterchainInfoForAccountState : &LiteQuery::continue_getMasterchainInfo;
td::actor::send_closure_later(Self, func, std::move(pair.first),
pair.second, mode);
}
});
}
void LiteQuery::gotMasterchainInfoForAccountState(Ref<ton::validator::MasterchainState> mc_state, BlockIdExt blkid,
int mode) {
perform_getAccountState(blkid, acc_workchain_, acc_addr_, 0x80000000);
}
void LiteQuery::continue_getMasterchainInfo(Ref<ton::validator::MasterchainState> mc_state, BlockIdExt blkid,
int mode) {
LOG(INFO) << "obtained data for getMasterchainInfo() : last block = " << blkid.to_str();
@ -431,15 +455,25 @@ void LiteQuery::continue_getZeroState(BlockIdExt blkid, td::BufferSlice state) {
void LiteQuery::perform_sendMessage(td::BufferSlice data) {
LOG(INFO) << "started a sendMessage(<" << data.size() << " bytes>) liteserver query";
auto res = ton::validator::create_ext_message(std::move(data));
if (res.is_error()) {
abort_query(res.move_as_error());
return;
}
LOG(INFO) << "sending an external message to validator manager";
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);
finish_query(std::move(b));
td::actor::send_closure_later(
manager_, &ValidatorManager::check_external_message, data.clone(),
[Self = actor_id(this), data = std::move(data), manager = manager_](td::Result<td::Unit> res) {
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(data.clone());
if (crm.is_error()) {
//UNREACHABLE, checks in check_external_message,
td::actor::send_closure(Self, &LiteQuery::abort_query,
crm.move_as_error());
}
LOG(INFO) << "sending an external message to validator manager";
td::actor::send_closure_later(manager, &ValidatorManager::send_external_message, crm.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));
}
});
}
bool LiteQuery::request_mc_block_data(BlockIdExt blkid) {
@ -702,6 +736,10 @@ void LiteQuery::continue_getAccountState_0(Ref<ton::validator::MasterchainState>
request_mc_block_data(blkid);
}
void LiteQuery::perform_fetchAccountState() {
perform_getMasterchainInfo(-1);
}
void LiteQuery::perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode,
td::int64 method_id, td::BufferSlice params) {
LOG(INFO) << "started a runSmcMethod(" << blkid.to_str() << ", " << workchain << ", " << addr.to_hex() << ", "
@ -1010,6 +1048,19 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) {
}
vm::AugmentedDictionary accounts_dict{vm::load_cell_slice_ref(sstate.accounts), 256, block::tlb::aug_ShardAccounts};
auto acc_csr = accounts_dict.lookup(acc_addr_);
if (mode_ & 0x80000000) {
auto config = block::ConfigInfo::extract_config(mc_state_->root_cell(), 0xFFFF);
if (config.is_error()) {
fatal_error(config.move_as_error());
return;
}
auto rconfig = config.move_as_ok();
acc_state_promise_.set_value(std::make_tuple(
std::move(acc_csr), sstate.gen_utime, sstate.gen_lt, std::move(rconfig)
));
return;
}
Ref<vm::Cell> acc_root;
if (acc_csr.not_null()) {
acc_root = acc_csr->prefetch_ref();

View file

@ -26,6 +26,8 @@
#include "block.hpp"
#include "shard.hpp"
#include "proof.hpp"
#include "block/block-auto.h"
namespace ton {
@ -37,6 +39,9 @@ class LiteQuery : public td::actor::Actor {
td::actor::ActorId<ton::validator::ValidatorManager> manager_;
td::Timestamp timeout_;
td::Promise<td::BufferSlice> promise_;
td::Promise<std::tuple<td::Ref<vm::CellSlice>,UnixTime,LogicalTime,std::unique_ptr<block::ConfigInfo>>> acc_state_promise_;
int pending_{0};
int mode_{0};
WorkchainId acc_workchain_;
@ -71,9 +76,14 @@ class LiteQuery : public td::actor::Actor {
}; // version 1.1; +1 = build block proof chains, +2 = masterchainInfoExt, +4 = runSmcMethod
LiteQuery(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<td::BufferSlice> promise);
LiteQuery(WorkchainId wc, StdSmcAddress acc_addr, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<std::tuple<td::Ref<vm::CellSlice>,UnixTime,LogicalTime,std::unique_ptr<block::ConfigInfo>>> promise);
static void run_query(td::BufferSlice data, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<td::BufferSlice> promise);
static void fetch_account_state(WorkchainId wc, StdSmcAddress acc_addr, td::actor::ActorId<ton::validator::ValidatorManager> manager,
td::Promise<std::tuple<td::Ref<vm::CellSlice>,UnixTime,LogicalTime,std::unique_ptr<block::ConfigInfo>>> promise);
private:
bool fatal_error(td::Status error);
bool fatal_error(std::string err_msg, int err_code = -400);
@ -87,6 +97,7 @@ class LiteQuery : public td::actor::Actor {
void perform_getVersion();
void perform_getMasterchainInfo(int mode);
void continue_getMasterchainInfo(Ref<MasterchainState> mc_state, BlockIdExt blkid, int mode);
void gotMasterchainInfoForAccountState(Ref<MasterchainState> mc_state, BlockIdExt blkid, int mode);
void perform_getBlock(BlockIdExt blkid);
void continue_getBlock(BlockIdExt blkid, Ref<BlockData> block);
void perform_getBlockHeader(BlockIdExt blkid, int mode);
@ -99,6 +110,7 @@ class LiteQuery : public td::actor::Actor {
void continue_getAccountState_0(Ref<MasterchainState> mc_state, BlockIdExt blkid);
void continue_getAccountState();
void finish_getAccountState(td::BufferSlice shard_proof);
void perform_fetchAccountState();
void perform_runSmcMethod(BlockIdExt blkid, WorkchainId workchain, StdSmcAddress addr, int mode, td::int64 method_id,
td::BufferSlice params);
void finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice state_proof, Ref<vm::Cell> acc_root,

View file

@ -35,6 +35,8 @@ class ExtMessage : public td::CntObject {
virtual td::BufferSlice serialize() const = 0;
virtual td::Ref<vm::Cell> root_cell() const = 0;
virtual Hash hash() const = 0;
virtual ton::WorkchainId wc() const = 0;
virtual ton::StdSmcAddress addr() const = 0;
};
} // namespace validator

View file

@ -374,13 +374,25 @@ void ValidatorManagerImpl::new_external_message(td::BufferSlice data) {
VLOG(VALIDATOR_NOTICE) << "dropping bad ihr message: " << R.move_as_error();
return;
}
auto M = std::make_unique<MessageExt<ExtMessage>>(R.move_as_ok());
auto id = M->ext_id();
if (ext_messages_hashes_.count(id.hash) == 0) {
ext_messages_.emplace(id, std::move(M));
ext_messages_hashes_.emplace(id.hash, id);
add_external_message(R.move_as_ok());
}
void ValidatorManagerImpl::add_external_message(td::Ref<ExtMessage> msg) {
auto message = std::make_unique<MessageExt<ExtMessage>>(msg);
auto id = message->ext_id();
auto address = message->address();
unsigned long per_address_limit = 256;
if(ext_addr_messages_.count(address) < per_address_limit) {
if (ext_messages_hashes_.count(id.hash) == 0) {
ext_messages_.emplace(id, std::move(message));
ext_messages_hashes_.emplace(id.hash, id);
ext_addr_messages_[address].emplace(id.hash, id);
}
}
}
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::new_ihr_message(td::BufferSlice data) {
if (!is_validator()) {
@ -759,6 +771,7 @@ void ValidatorManagerImpl::get_external_messages(ShardIdFull shard,
break;
}
if (it->second->expired()) {
ext_addr_messages_[it->second->address()].erase(it->first.hash);
ext_messages_hashes_.erase(it->first.hash);
it = ext_messages_.erase(it);
continue;
@ -807,17 +820,20 @@ void ValidatorManagerImpl::complete_external_messages(std::vector<ExtMessage::Ha
for (auto &hash : to_delete) {
auto it = ext_messages_hashes_.find(hash);
if (it != ext_messages_hashes_.end()) {
ext_addr_messages_[ext_messages_[it->second]->address()].erase(it->first);
CHECK(ext_messages_.erase(it->second));
ext_messages_hashes_.erase(it);
}
}
unsigned long soft_mempool_limit = 1024;
for (auto &hash : to_delay) {
auto it = ext_messages_hashes_.find(hash);
if (it != ext_messages_hashes_.end()) {
auto it2 = ext_messages_.find(it->second);
if (it2->second->can_postpone()) {
if ((ext_messages_.size() < soft_mempool_limit) && it2->second->can_postpone()) {
it2->second->postpone();
} else {
ext_addr_messages_[it2->second->address()].erase(it2->first.hash);
ext_messages_.erase(it2);
ext_messages_hashes_.erase(it);
}
@ -1352,6 +1368,7 @@ void ValidatorManagerImpl::send_get_next_key_blocks_request(BlockIdExt block_id,
void ValidatorManagerImpl::send_external_message(td::Ref<ExtMessage> message) {
callback_->send_ext_message(message->shard(), message->serialize());
add_external_message(std::move(message));
}
void ValidatorManagerImpl::send_ihr_message(td::Ref<IhrMessage> message) {

View file

@ -74,6 +74,9 @@ class MessageExt {
auto hash() const {
return message_->hash();
}
auto address() const {
return std::make_pair(message_->wc(), message_->addr());
}
bool is_active() {
if (!active_) {
if (reactivate_at_.is_in_past()) {
@ -210,6 +213,7 @@ class ValidatorManagerImpl : public ValidatorManager {
// DATA FOR COLLATOR
std::map<ShardTopBlockDescriptionId, td::Ref<ShardTopBlockDescription>> shard_blocks_;
std::map<MessageId<ExtMessage>, std::unique_ptr<MessageExt<ExtMessage>>> ext_messages_;
std::map<std::pair<ton::WorkchainId,ton::StdSmcAddress>, std::map<ExtMessage::Hash, MessageId<ExtMessage>>> ext_addr_messages_;
std::map<ExtMessage::Hash, MessageId<ExtMessage>> ext_messages_hashes_;
// IHR ?
std::map<MessageId<IhrMessage>, std::unique_ptr<MessageExt<IhrMessage>>> ihr_messages_;
@ -327,9 +331,9 @@ 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 {
promise.set_value(td::Unit());
}
void add_external_message(td::Ref<ExtMessage> message);
void check_external_message(td::BufferSlice data, td::Promise<td::Unit> promise) override;
void new_ihr_message(td::BufferSlice data) override;
void new_shard_block(BlockIdExt block_id, CatchainSeqno cc_seqno, td::BufferSlice data) override;