1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 19:22:37 +00:00

Limit account storage size (#530)

* Limit size of an account

* Bugfix

* Don't check size for special accounts

* Improve timeouts in collator and validator

Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
EmelyanenkoK 2022-11-30 08:40:19 +03:00 committed by GitHub
parent a4a3ea2b77
commit d8dd75ec83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 195 additions and 84 deletions

View file

@ -753,6 +753,8 @@ _ MisbehaviourPunishmentConfig = ConfigParam 40;
size_limits_config#01 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells:uint32 max_vm_data_depth:uint16
max_ext_msg_size:uint32 max_ext_msg_depth:uint16 = SizeLimitsConfig;
size_limits_config_v2#02 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells:uint32 max_vm_data_depth:uint16
max_ext_msg_size:uint32 max_ext_msg_depth:uint16 max_acc_state_cells:uint32 max_acc_state_bits:uint32 = SizeLimitsConfig;
_ SizeLimitsConfig = ConfigParam 43;
oracle_bridge_params#_ bridge_address:bits256 oracle_mutlisig_address:bits256 oracles:(HashmapE 256 uint256) external_chain_address:bits256 = OracleBridgeParams;

View file

@ -1919,16 +1919,29 @@ td::Result<SizeLimitsConfig> Config::get_size_limits_config() const {
if (param.is_null()) {
return limits;
}
gen::SizeLimitsConfig::Record rec;
if (!tlb::unpack_cell(param, rec)) {
auto unpack_v1 = [&](auto& rec) {
limits.max_msg_bits = rec.max_msg_bits;
limits.max_msg_cells = rec.max_msg_cells;
limits.max_library_cells = rec.max_library_cells;
limits.max_vm_data_depth = static_cast<td::uint16>(rec.max_vm_data_depth);
limits.ext_msg_limits.max_size = rec.max_ext_msg_size;
limits.ext_msg_limits.max_depth = static_cast<td::uint16>(rec.max_ext_msg_depth);
};
auto unpack_v2 = [&](auto& rec) {
unpack_v1(rec);
limits.max_acc_state_bits = rec.max_acc_state_bits;
limits.max_acc_state_cells = rec.max_acc_state_cells;
};
gen::SizeLimitsConfig::Record_size_limits_config rec_v1;
gen::SizeLimitsConfig::Record_size_limits_config_v2 rec_v2;
if (tlb::unpack_cell(param, rec_v1)) {
unpack_v1(rec_v1);
} else if (tlb::unpack_cell(param, rec_v2)) {
unpack_v2(rec_v2);
} else {
return td::Status::Error("configuration parameter 43 is invalid");
}
limits.max_msg_bits = rec.max_msg_bits;
limits.max_msg_cells = rec.max_msg_cells;
limits.max_library_cells = rec.max_library_cells;
limits.max_vm_data_depth = static_cast<td::uint16>(rec.max_vm_data_depth);
limits.ext_msg_limits.max_size = rec.max_ext_msg_size;
limits.ext_msg_limits.max_depth = static_cast<td::uint16>(rec.max_ext_msg_depth);
return limits;
}

View file

@ -387,6 +387,8 @@ struct SizeLimitsConfig {
td::uint32 max_library_cells = 1000;
td::uint16 max_vm_data_depth = 512;
ExtMsgLimits ext_msg_limits;
td::uint32 max_acc_state_cells = 1 << 16;
td::uint32 max_acc_state_bits = (1 << 16) * 1023;
};
struct CatchainValidatorsConfig {

View file

@ -460,7 +460,6 @@ bool Account::deactivate() {
return true;
}
bool Account::belongs_to_shard(ton::ShardIdFull shard) const {
return workchain == shard.workchain && ton::shard_is_ancestor(shard.shard, addr);
}
@ -1126,6 +1125,25 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
ap.total_action_fees = td::zero_refint();
ap.reserved_balance.set_zero();
td::Ref<vm::Cell> old_code = new_code, old_data = new_data, old_library = new_library;
auto enforce_state_size_limits = [&]() {
if (account.is_special) {
return true;
}
if (!check_state_size_limit(cfg)) {
// Rollback changes to state, fail action phase
LOG(INFO) << "Account state size exceeded limits";
new_storage_stat.clear();
new_code = old_code;
new_data = old_data;
new_library = old_library;
ap.result_code = 50;
ap.state_size_too_big = true;
return false;
}
return true;
};
int n = 0;
while (true) {
ap.action_list.push_back(list);
@ -1201,9 +1219,21 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
ap.no_funds = true;
}
LOG(DEBUG) << "invalid action " << ap.result_arg << " in action list: error code " << ap.result_code;
// This is reuqired here because changes to libraries are applied even if actipn phase fails
enforce_state_size_limits();
return true;
}
}
end_lt = ap.end_lt;
if (ap.new_code.not_null()) {
new_code = ap.new_code;
}
new_data = compute_phase->new_data; // tentative persistent data update applied
if (!enforce_state_size_limits()) {
return true;
}
ap.result_arg = 0;
ap.result_code = 0;
CHECK(ap.remaining_balance.grams->sgn() >= 0);
@ -1217,12 +1247,7 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
was_deleted = true;
}
ap.success = true;
end_lt = ap.end_lt;
out_msgs = std::move(ap.out_msgs);
if (ap.new_code.not_null()) {
new_code = ap.new_code;
}
new_data = compute_phase->new_data; // tentative persistent data update applied
total_fees +=
ap.total_action_fees; // NB: forwarding fees are not accounted here (they are not collected by the validators in this transaction)
balance = ap.remaining_balance;
@ -1811,6 +1836,35 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap,
return 0;
}
bool Transaction::check_state_size_limit(const ActionPhaseConfig& cfg) {
auto cell_equal = [](const td::Ref<vm::Cell>& a, const td::Ref<vm::Cell>& b) -> bool {
if (a.is_null()) {
return b.is_null();
}
if (b.is_null()) {
return false;
}
return a->get_hash() == b->get_hash();
};
if (cell_equal(account.code, new_code) && cell_equal(account.data, new_data) &&
cell_equal(account.library, new_library)) {
return true;
}
// new_storage_stat is used here beause these stats will be reused in compute_state()
new_storage_stat.limit_cells = cfg.size_limits.max_acc_state_cells;
new_storage_stat.limit_bits = cfg.size_limits.max_acc_state_bits;
new_storage_stat.add_used_storage(new_code);
new_storage_stat.add_used_storage(new_data);
new_storage_stat.add_used_storage(new_library);
if (acc_status == Account::acc_active) {
new_storage_stat.clear_limit();
} else {
new_storage_stat.clear();
}
return new_storage_stat.cells <= cfg.size_limits.max_acc_state_cells &&
new_storage_stat.bits <= cfg.size_limits.max_acc_state_bits;
}
bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
if (in_msg.is_null() || !bounce_enabled) {
return false;
@ -2035,7 +2089,7 @@ bool Transaction::compute_state() {
stats = new_stats.unwrap();
} else {
td::Timer timer;
CHECK(stats.compute_used_storage(Ref<vm::Cell>(storage)));
CHECK(stats.add_used_storage(Ref<vm::Cell>(storage)));
if (timer.elapsed() > 0.1) {
LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
}

View file

@ -184,6 +184,7 @@ struct ActionPhase {
bool code_changed{false};
bool action_list_invalid{false};
bool acc_delete_req{false};
bool state_size_too_big{false};
enum { acst_unchanged = 0, acst_frozen = 2, acst_deleted = 3 };
int acc_status_change{acst_unchanged};
td::RefInt256 total_fwd_fees; // all fees debited from the account
@ -351,6 +352,7 @@ struct Transaction {
std::vector<Ref<vm::Cell>> compute_vm_libraries(const ComputePhaseConfig& cfg);
bool prepare_compute_phase(const ComputePhaseConfig& cfg);
bool prepare_action_phase(const ActionPhaseConfig& cfg);
bool check_state_size_limit(const ActionPhaseConfig& cfg);
bool prepare_bounce_phase(const ActionPhaseConfig& cfg);
bool compute_state();
bool serialize();

View file

@ -1039,9 +1039,15 @@ bool CellStorageStat::add_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup,
bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) {
if (!(skip_count_root & 1)) {
++cells;
if (cells > limit_cells) {
return false;
}
}
if (!(skip_count_root & 2)) {
bits += cs.size();
if (bits > limit_bits) {
return false;
}
}
for (unsigned i = 0; i < cs.size_refs(); i++) {
if (!add_used_storage(cs.prefetch_ref(i), kill_dup)) {
@ -1054,9 +1060,15 @@ bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, unsig
bool CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) {
if (!(skip_count_root & 1)) {
++cells;
if (cells > limit_cells) {
return false;
}
}
if (!(skip_count_root & 2)) {
bits += cs.size();
if (bits > limit_bits) {
return false;
}
}
while (cs.size_refs()) {
if (!add_used_storage(cs.fetch_ref(), kill_dup)) {

View file

@ -117,8 +117,13 @@ struct CellStorageStat {
}
void clear() {
cells = bits = public_cells = 0;
clear_limit();
clear_seen();
}
void clear_limit() {
limit_cells = std::numeric_limits<unsigned long long>::max();
limit_bits = std::numeric_limits<unsigned long long>::max();
}
bool compute_used_storage(Ref<vm::CellSlice> cs_ref, bool kill_dup = true, unsigned skip_count_root = 0);
bool compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
bool compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
@ -128,6 +133,9 @@ struct CellStorageStat {
bool add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0);
bool add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0);
bool add_used_storage(Ref<vm::Cell> cell, bool kill_dup = true, unsigned skip_count_root = 0);
unsigned long long limit_cells = std::numeric_limits<unsigned long long>::max();
unsigned long long limit_bits = std::numeric_limits<unsigned long long>::max();
};
struct VmStorageStat {

View file

@ -71,8 +71,8 @@ Collator::Collator(ShardIdFull shard, bool is_hardfork, UnixTime min_ts, BlockId
, 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() {
@ -1561,30 +1561,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();
@ -1733,6 +1725,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");
@ -2250,15 +2245,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 {};
@ -2285,16 +2276,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) {
@ -2308,51 +2296,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);
}
@ -3188,7 +3183,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

@ -66,8 +66,8 @@ ValidateQuery::ValidateQuery(ShardIdFull shard, UnixTime min_ts, BlockIdExt min_
, 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);
}) {
proc_hash_.zero();
}
@ -1004,6 +1004,16 @@ bool ValidateQuery::check_this_shard_mc_info() {
bool ValidateQuery::compute_prev_state() {
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_) {
@ -4113,6 +4123,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;
@ -4318,7 +4331,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");
@ -4491,7 +4505,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());
}
@ -4974,7 +4989,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

@ -368,6 +368,14 @@ class ValidateQuery : public td::actor::Actor {
bool check_one_shard_fee(ShardIdFull shard, const block::CurrencyCollection& fees,
const block::CurrencyCollection& create);
bool check_mc_block_extra();
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

@ -108,7 +108,7 @@ void ValidatorGroup::validate_block_candidate(td::uint32 round_id, BlockCandidat
VLOG(VALIDATOR_DEBUG) << "validating block candidate " << next_block_id;
block.id = next_block_id;
run_validate_query(shard_, min_ts_, min_masterchain_block_id_, prev_block_ids_, std::move(block), validator_set_,
manager_, td::Timestamp::in(10.0), std::move(P));
manager_, td::Timestamp::in(15.0), std::move(P));
}
void ValidatorGroup::accept_block_candidate(td::uint32 round_id, PublicKeyHash src, td::BufferSlice block_data,