mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +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
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue