diff --git a/crypto/block/block.cpp b/crypto/block/block.cpp index 1131213c..9a3dba60 100644 --- a/crypto/block/block.cpp +++ b/crypto/block/block.cpp @@ -715,7 +715,7 @@ td::uint64 BlockLimitStatus::estimate_block_size(const vm::NewCellStorageStat::S sum += *extra; } return 2000 + (sum.bits >> 3) + sum.cells * 12 + sum.internal_refs * 3 + sum.external_refs * 40 + accounts * 200 + - transactions * 200 + (extra ? 200 : 0) + extra_out_msgs * 300; + transactions * 200 + (extra ? 200 : 0) + extra_out_msgs * 300 + extra_library_diff * 700; } int BlockLimitStatus::classify() const { diff --git a/crypto/block/block.h b/crypto/block/block.h index 19d99e6a..09169429 100644 --- a/crypto/block/block.h +++ b/crypto/block/block.h @@ -262,6 +262,7 @@ struct BlockLimitStatus { td::uint64 gas_used{}; vm::NewCellStorageStat st_stat; unsigned accounts{}, transactions{}, extra_out_msgs{}; + unsigned extra_library_diff{}; // Number of public libraries in deleted/frozen accounts BlockLimitStatus(const BlockLimits& limits_, ton::LogicalTime lt = 0) : limits(limits_), cur_lt(std::max(limits_.start_lt, lt)) { } @@ -271,6 +272,7 @@ struct BlockLimitStatus { transactions = accounts = 0; gas_used = 0; extra_out_msgs = 0; + extra_library_diff = 0; } td::uint64 estimate_block_size(const vm::NewCellStorageStat::Stat* extra = nullptr) const; int classify() const; diff --git a/crypto/block/block.tlb b/crypto/block/block.tlb index 1b6f72a3..4b36f13b 100644 --- a/crypto/block/block.tlb +++ b/crypto/block/block.tlb @@ -780,7 +780,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; + max_ext_msg_size:uint32 max_ext_msg_depth:uint16 max_acc_state_cells:uint32 max_acc_state_bits:uint32 + max_acc_public_libraries:uint32 = SizeLimitsConfig; _ SizeLimitsConfig = ConfigParam 43; // key is [ wc:int32 addr:uint256 ] diff --git a/crypto/block/mc-config.cpp b/crypto/block/mc-config.cpp index 02c6e45b..08be5c88 100644 --- a/crypto/block/mc-config.cpp +++ b/crypto/block/mc-config.cpp @@ -1934,6 +1934,7 @@ td::Result Config::get_size_limits_config() const { unpack_v1(rec); limits.max_acc_state_bits = rec.max_acc_state_bits; limits.max_acc_state_cells = rec.max_acc_state_cells; + limits.max_acc_public_libraries = rec.max_acc_public_libraries; }; gen::SizeLimitsConfig::Record_size_limits_config rec_v1; gen::SizeLimitsConfig::Record_size_limits_config_v2 rec_v2; diff --git a/crypto/block/mc-config.h b/crypto/block/mc-config.h index b29e3792..caab93f3 100644 --- a/crypto/block/mc-config.h +++ b/crypto/block/mc-config.h @@ -389,6 +389,7 @@ struct SizeLimitsConfig { ExtMsgLimits ext_msg_limits; td::uint32 max_acc_state_cells = 1 << 16; td::uint32 max_acc_state_bits = (1 << 16) * 1023; + td::uint32 max_acc_public_libraries = 256; }; struct CatchainValidatorsConfig { diff --git a/crypto/block/transaction.cpp b/crypto/block/transaction.cpp index 49c853a9..05df6371 100644 --- a/crypto/block/transaction.cpp +++ b/crypto/block/transaction.cpp @@ -2500,8 +2500,28 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, return 0; } +/** + * Calculates the number of public libraries in the dictionary. + * + * @param libraries The dictionary of account libraries. + * + * @returns The number of public libraries in the dictionary. + */ +static td::uint32 get_public_libraries_count(const td::Ref& libraries) { + td::uint32 count = 0; + vm::Dictionary dict{libraries, 256}; + dict.check_for_each([&](td::Ref value, td::ConstBitPtr key, int) { + if (block::is_public_library(key, std::move(value))) { + ++count; + } + return true; + }); + return count; +} + /** * Checks that the new account state fits in the limits. + * This function is not called for special accounts. * * @param cfg The configuration for the action phase. * @@ -2547,10 +2567,15 @@ td::Status Transaction::check_state_limits(const ActionPhaseConfig& cfg) { } 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 - ? td::Status::OK() - : td::Status::Error("state too big"); + if (new_storage_stat.cells > cfg.size_limits.max_acc_state_cells || + new_storage_stat.bits > cfg.size_limits.max_acc_state_bits) { + return td::Status::Error("account state is too big"); + } + if (account.is_masterchain() && !cell_equal(account.library, new_library) && + get_public_libraries_count(new_library) > cfg.size_limits.max_acc_public_libraries) { + return td::Status::Error("too many public libraries"); + } + return td::Status::OK(); } /** @@ -3135,8 +3160,13 @@ bool Transaction::update_limits(block::BlockLimitStatus& blimst, bool with_size) return false; } if (with_size) { - return blimst.add_proof(new_total_state) && blimst.add_cell(root) && blimst.add_transaction() && - blimst.add_account(is_first); + if (!(blimst.add_proof(new_total_state) && blimst.add_cell(root) && blimst.add_transaction() && + blimst.add_account(is_first))) { + return false; + } + if (account.is_masterchain() && (was_frozen || was_deleted)) { + blimst.extra_library_diff += get_public_libraries_count(account.orig_library); + } } return true; } diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index d133278f..b72292bb 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -4310,7 +4310,7 @@ bool Collator::update_public_libraries() { } } } - if (libraries_changed_ && verbosity >= 2 * 0) { + if (libraries_changed_ && verbosity >= 2) { std::cerr << "New public libraries: "; block::gen::t_HashmapE_256_LibDescr.print(std::cerr, shard_libraries_->get_root()); shard_libraries_->get_root()->print_rec(std::cerr);