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:
parent
a4a3ea2b77
commit
d8dd75ec83
11 changed files with 195 additions and 84 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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() +
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue