diff --git a/crypto/block/create-state.cpp b/crypto/block/create-state.cpp index 7a734c3a..a7500713 100644 --- a/crypto/block/create-state.cpp +++ b/crypto/block/create-state.cpp @@ -308,7 +308,7 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref code, R THRERR("cannot create smart-contract AccountStorage"); Ref storage = cb.finalize(); vm::CellStorageStat stats; - PDO(stats.compute_used_storage(Ref(storage))); + PDO(stats.compute_used_storage(Ref(storage)).is_ok()); if (verbosity > 2) { std::cerr << "storage is:\n"; vm::load_cell_slice(storage).print_rec(std::cerr); diff --git a/crypto/block/transaction.cpp b/crypto/block/transaction.cpp index 7607ef81..47ea4e47 100644 --- a/crypto/block/transaction.cpp +++ b/crypto/block/transaction.cpp @@ -590,15 +590,19 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* in_msg_type = 2; in_msg_extern = true; // compute forwarding fees for this external message - vm::CellStorageStat sstat; // for message size - sstat.compute_used_storage(cs); // message body - sstat.bits -= cs.size(); // bits in the root cells are free - sstat.cells--; // the root cell itself is not counted as a cell + vm::CellStorageStat sstat; // for message size + auto cell_info = sstat.compute_used_storage(cs).move_as_ok(); // message body + sstat.bits -= cs.size(); // bits in the root cells are free + sstat.cells--; // the root cell itself is not counted as a cell LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits"; if (sstat.bits > cfg->size_limits.max_msg_bits || sstat.cells > cfg->size_limits.max_msg_cells) { LOG(DEBUG) << "inbound external message too large, invalid"; return false; } + if (cell_info.max_merkle_depth > max_allowed_merkle_depth) { + LOG(DEBUG) << "inbound external message has too big merkle depth, invalid"; + return false; + } // fetch message pricing info CHECK(cfg); const MsgPrices& msg_prices = cfg->fetch_msg_prices(account.is_masterchain()); @@ -1157,19 +1161,20 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) { ap.reserved_balance.set_zero(); td::Ref old_code = new_code, old_data = new_data, old_library = new_library; - auto enforce_state_size_limits = [&]() { + auto enforce_state_limits = [&]() { if (account.is_special) { return true; } - if (!check_state_size_limit(cfg)) { + auto S = check_state_limits(cfg); + if (S.is_error()) { // Rollback changes to state, fail action phase - LOG(INFO) << "Account state size exceeded limits"; + LOG(INFO) << "Account state size exceeded limits: " << S.move_as_error(); 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; + ap.state_exceeds_limits = true; return false; } return true; @@ -1250,8 +1255,8 @@ 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(); + // This is reuqired here because changes to libraries are applied even if action phase fails + enforce_state_limits(); return true; } } @@ -1261,7 +1266,7 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) { new_code = ap.new_code; } new_data = compute_phase->new_data; // tentative persistent data update applied - if (!enforce_state_size_limits()) { + if (!enforce_state_limits()) { return true; } @@ -1334,8 +1339,8 @@ int Transaction::try_action_change_library(vm::CellSlice& cs, ActionPhase& ap, c return 41; } vm::CellStorageStat sstat; - sstat.compute_used_storage(lib_ref); - if (sstat.cells > cfg.size_limits.max_library_cells) { + auto cell_info = sstat.compute_used_storage(lib_ref).move_as_ok(); + if (sstat.cells > cfg.size_limits.max_library_cells || cell_info.max_merkle_depth > max_allowed_merkle_depth) { return 43; } vm::CellBuilder cb; @@ -1608,16 +1613,27 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, // compute size of message vm::CellStorageStat sstat; // for message size // preliminary storage estimation of the resulting message - sstat.add_used_storage(msg.init, true, 3); // message init - sstat.add_used_storage(msg.body, true, 3); // message body (the root cell itself is not counted) + unsigned max_merkle_depth = 0; + auto add_used_storage = [&](const auto& x, unsigned skip_root_count) { + if (x.not_null()) { + auto res = sstat.add_used_storage(x, true, skip_root_count).move_as_ok(); + max_merkle_depth = std::max(max_merkle_depth, res.max_merkle_depth); + } + }; + add_used_storage(msg.init, 3); // message init + add_used_storage(msg.body, 3); // message body (the root cell itself is not counted) if (!ext_msg) { - sstat.add_used_storage(info.value->prefetch_ref()); + add_used_storage(info.value->prefetch_ref(), 0); } LOG(DEBUG) << "storage paid for a message: " << sstat.cells << " cells, " << sstat.bits << " bits"; if (sstat.bits > cfg.size_limits.max_msg_bits || sstat.cells > cfg.size_limits.max_msg_cells) { LOG(DEBUG) << "message too large, invalid"; return skip_invalid ? 0 : 40; } + if (max_merkle_depth > max_allowed_merkle_depth) { + LOG(DEBUG) << "message has too big merkle depth, invalid"; + return skip_invalid ? 0 : 40; + } // compute forwarding fees auto fees_c = msg_prices.compute_fwd_ihr_fees(sstat.cells, sstat.bits, info.ihr_disabled); @@ -1869,7 +1885,7 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, return 0; } -bool Transaction::check_state_size_limit(const ActionPhaseConfig& cfg) { +td::Status Transaction::check_state_limits(const ActionPhaseConfig& cfg) { auto cell_equal = [](const td::Ref& a, const td::Ref& b) -> bool { if (a.is_null()) { return b.is_null(); @@ -1881,21 +1897,36 @@ bool Transaction::check_state_size_limit(const ActionPhaseConfig& cfg) { }; if (cell_equal(account.code, new_code) && cell_equal(account.data, new_data) && cell_equal(account.library, new_library)) { - return true; + return td::Status::OK(); } // 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); + td::Timer timer; + auto add_used_storage = [&](const td::Ref& cell) -> td::Status { + if (cell.not_null()) { + TRY_RESULT(res, new_storage_stat.add_used_storage(cell)); + if (res.max_merkle_depth > max_allowed_merkle_depth) { + return td::Status::Error("too big merkle depth"); + } + } + return td::Status::OK(); + }; + TRY_STATUS(add_used_storage(new_code)); + TRY_STATUS(add_used_storage(new_data)); + TRY_STATUS(add_used_storage(new_library)); + if (timer.elapsed() > 0.1) { + LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s"; + } 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; + new_storage_stat.bits <= cfg.size_limits.max_acc_state_bits + ? td::Status::OK() + : td::Status::Error("state too big"); } bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) { @@ -2124,7 +2155,7 @@ bool Transaction::compute_state() { stats = new_stats.unwrap(); } else { td::Timer timer; - CHECK(stats.add_used_storage(Ref(storage))); + stats.add_used_storage(Ref(storage)).ensure(); if (timer.elapsed() > 0.1) { LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s"; } diff --git a/crypto/block/transaction.h b/crypto/block/transaction.h index 2e4463bd..6346ddcd 100644 --- a/crypto/block/transaction.h +++ b/crypto/block/transaction.h @@ -191,7 +191,7 @@ struct ActionPhase { bool code_changed{false}; bool action_list_invalid{false}; bool acc_delete_req{false}; - bool state_size_too_big{false}; + bool state_exceeds_limits{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 @@ -295,6 +295,7 @@ struct Account { namespace transaction { struct Transaction { + static constexpr unsigned max_allowed_merkle_depth = 2; enum { tr_none, tr_ord, @@ -360,7 +361,7 @@ struct Transaction { std::vector> 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); + td::Status check_state_limits(const ActionPhaseConfig& cfg); bool prepare_bounce_phase(const ActionPhaseConfig& cfg); bool compute_state(); bool serialize(); diff --git a/crypto/vm/boc.cpp b/crypto/vm/boc.cpp index f438d480..11583ede 100644 --- a/crypto/vm/boc.cpp +++ b/crypto/vm/boc.cpp @@ -1008,27 +1008,40 @@ td::Result std_boc_serialize_multi(std::vector> roots * */ -bool CellStorageStat::compute_used_storage(Ref cs_ref, bool kill_dup, unsigned skip_count_root) { +td::Result CellStorageStat::compute_used_storage(Ref cs_ref, bool kill_dup, + unsigned skip_count_root) { clear(); - return add_used_storage(std::move(cs_ref), kill_dup, skip_count_root) && clear_seen(); + TRY_RESULT(res, add_used_storage(std::move(cs_ref), kill_dup, skip_count_root)); + clear_seen(); + return res; } -bool CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) { +td::Result CellStorageStat::compute_used_storage(const CellSlice& cs, bool kill_dup, + unsigned skip_count_root) { clear(); - return add_used_storage(cs, kill_dup, skip_count_root) && clear_seen(); + TRY_RESULT(res, add_used_storage(cs, kill_dup, skip_count_root)); + clear_seen(); + return res; } -bool CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) { +td::Result CellStorageStat::compute_used_storage(CellSlice&& cs, bool kill_dup, + unsigned skip_count_root) { clear(); - return add_used_storage(std::move(cs), kill_dup, skip_count_root) && clear_seen(); + TRY_RESULT(res, add_used_storage(std::move(cs), kill_dup, skip_count_root)); + clear_seen(); + return res; } -bool CellStorageStat::compute_used_storage(Ref cell, bool kill_dup, unsigned skip_count_root) { +td::Result CellStorageStat::compute_used_storage(Ref cell, bool kill_dup, + unsigned skip_count_root) { clear(); - return add_used_storage(std::move(cell), kill_dup, skip_count_root) && clear_seen(); + TRY_RESULT(res, add_used_storage(std::move(cell), kill_dup, skip_count_root)); + clear_seen(); + return res; } -bool CellStorageStat::add_used_storage(Ref cs_ref, bool kill_dup, unsigned skip_count_root) { +td::Result CellStorageStat::add_used_storage(Ref cs_ref, bool kill_dup, + unsigned skip_count_root) { if (cs_ref->is_unique()) { return add_used_storage(std::move(cs_ref.unique_write()), kill_dup, skip_count_root); } else { @@ -1036,56 +1049,67 @@ bool CellStorageStat::add_used_storage(Ref cs_ref, bool kill_dup, } } -bool CellStorageStat::add_used_storage(const CellSlice& cs, bool kill_dup, unsigned skip_count_root) { +td::Result 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; + return td::Status::Error("too many cells"); } } if (!(skip_count_root & 2)) { bits += cs.size(); if (bits > limit_bits) { - return false; + return td::Status::Error("too many bits"); } } + CellInfo res; for (unsigned i = 0; i < cs.size_refs(); i++) { - if (!add_used_storage(cs.prefetch_ref(i), kill_dup)) { - return false; - } + TRY_RESULT(child, add_used_storage(cs.prefetch_ref(i), kill_dup)); + res.max_merkle_depth = std::max(res.max_merkle_depth, child.max_merkle_depth); } - return true; + if (cs.special_type() == CellTraits::SpecialType::MerkleProof || + cs.special_type() == CellTraits::SpecialType::MerkleUpdate) { + ++res.max_merkle_depth; + } + return res; } -bool CellStorageStat::add_used_storage(CellSlice&& cs, bool kill_dup, unsigned skip_count_root) { +td::Result 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; + return td::Status::Error("too many cells"); } } if (!(skip_count_root & 2)) { bits += cs.size(); if (bits > limit_bits) { - return false; + return td::Status::Error("too many bits"); } } + CellInfo res; while (cs.size_refs()) { - if (!add_used_storage(cs.fetch_ref(), kill_dup)) { - return false; - } + TRY_RESULT(child, add_used_storage(cs.fetch_ref(), kill_dup)); + res.max_merkle_depth = std::max(res.max_merkle_depth, child.max_merkle_depth); } - return true; + if (cs.special_type() == CellTraits::SpecialType::MerkleProof || + cs.special_type() == CellTraits::SpecialType::MerkleUpdate) { + ++res.max_merkle_depth; + } + return res; } -bool CellStorageStat::add_used_storage(Ref cell, bool kill_dup, unsigned skip_count_root) { +td::Result CellStorageStat::add_used_storage(Ref cell, bool kill_dup, + unsigned skip_count_root) { if (cell.is_null()) { - return false; + return td::Status::Error("cell is null"); } if (kill_dup) { - auto ins = seen.insert(cell->get_hash()); + auto ins = seen.emplace(cell->get_hash(), CellInfo{}); if (!ins.second) { - return true; + return ins.first->second; } } vm::CellSlice cs{vm::NoVm{}, std::move(cell)}; diff --git a/crypto/vm/boc.h b/crypto/vm/boc.h index dd74a6d1..c4e6de45 100644 --- a/crypto/vm/boc.h +++ b/crypto/vm/boc.h @@ -108,12 +108,14 @@ struct CellStorageStat { unsigned long long cells; unsigned long long bits; unsigned long long public_cells; - std::set seen; + struct CellInfo { + td::uint32 max_merkle_depth = 0; + }; + std::map seen; CellStorageStat() : cells(0), bits(0), public_cells(0) { } - bool clear_seen() { + void clear_seen() { seen.clear(); - return true; } void clear() { cells = bits = public_cells = 0; @@ -124,15 +126,16 @@ struct CellStorageStat { limit_cells = std::numeric_limits::max(); limit_bits = std::numeric_limits::max(); } - bool compute_used_storage(Ref 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); - bool compute_used_storage(Ref cell, bool kill_dup = true, unsigned skip_count_root = 0); + td::Result compute_used_storage(Ref cs_ref, bool kill_dup = true, + unsigned skip_count_root = 0); + td::Result compute_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0); + td::Result compute_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0); + td::Result compute_used_storage(Ref cell, bool kill_dup = true, unsigned skip_count_root = 0); - bool add_used_storage(Ref cs_ref, bool kill_dup = true, unsigned skip_count_root = 0); - 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 cell, bool kill_dup = true, unsigned skip_count_root = 0); + td::Result add_used_storage(Ref cs_ref, bool kill_dup = true, unsigned skip_count_root = 0); + td::Result add_used_storage(const CellSlice& cs, bool kill_dup = true, unsigned skip_count_root = 0); + td::Result add_used_storage(CellSlice&& cs, bool kill_dup = true, unsigned skip_count_root = 0); + td::Result add_used_storage(Ref cell, bool kill_dup = true, unsigned skip_count_root = 0); unsigned long long limit_cells = std::numeric_limits::max(); unsigned long long limit_bits = std::numeric_limits::max(); diff --git a/crypto/vm/cells/MerkleProof.cpp b/crypto/vm/cells/MerkleProof.cpp index aee34367..26dff787 100644 --- a/crypto/vm/cells/MerkleProof.cpp +++ b/crypto/vm/cells/MerkleProof.cpp @@ -39,7 +39,13 @@ class MerkleProofImpl { dfs_usage_tree(cell, usage_tree_->root_id()); is_prunned_ = [this](const Ref &cell) { return visited_cells_.count(cell->get_hash()) == 0; }; } - return dfs(cell, cell->get_level()); + try { + return dfs(cell, cell->get_level()); + } catch (CellBuilder::CellWriteError &) { + return {}; + } catch (CellBuilder::CellCreateError &) { + return {}; + } } private: @@ -119,6 +125,9 @@ Ref MerkleProof::generate(Ref cell, CellUsageTree *usage_tree) { return {}; } auto raw = generate_raw(std::move(cell), usage_tree); + if (raw.is_null()) { + return {}; + } return CellBuilder::create_merkle_proof(std::move(raw)); } @@ -384,21 +393,29 @@ bool MerkleProofBuilder::clear() { return true; } -Ref MerkleProofBuilder::extract_proof() const { - return MerkleProof::generate(orig_root, usage_tree.get()); +td::Result> MerkleProofBuilder::extract_proof() const { + Ref proof = MerkleProof::generate(orig_root, usage_tree.get()); + if (proof.is_null()) { + return td::Status::Error("cannot create Merkle proof"); + } + return proof; } bool MerkleProofBuilder::extract_proof_to(Ref &proof_root) const { - return orig_root.not_null() && (proof_root = extract_proof()).not_null(); + if (orig_root.is_null()) { + return false; + } + auto R = extract_proof(); + if (R.is_error()) { + return false; + } + proof_root = R.move_as_ok(); + return true; } td::Result MerkleProofBuilder::extract_proof_boc() const { - Ref proof_root = extract_proof(); - if (proof_root.is_null()) { - return td::Status::Error("cannot create Merkle proof"); - } else { - return std_boc_serialize(std::move(proof_root)); - } + TRY_RESULT(proof_root, extract_proof()); + return std_boc_serialize(std::move(proof_root)); } } // namespace vm diff --git a/crypto/vm/cells/MerkleProof.h b/crypto/vm/cells/MerkleProof.h index 4f2add6c..9c50fd07 100644 --- a/crypto/vm/cells/MerkleProof.h +++ b/crypto/vm/cells/MerkleProof.h @@ -63,7 +63,7 @@ class MerkleProofBuilder { Ref root() const { return usage_root; } - Ref extract_proof() const; + td::Result> extract_proof() const; bool extract_proof_to(Ref &proof_root) const; td::Result extract_proof_boc() const; }; diff --git a/crypto/vm/cells/MerkleUpdate.cpp b/crypto/vm/cells/MerkleUpdate.cpp index 3cc656c0..894612bd 100644 --- a/crypto/vm/cells/MerkleUpdate.cpp +++ b/crypto/vm/cells/MerkleUpdate.cpp @@ -221,6 +221,9 @@ Ref MerkleUpdate::generate(Ref from, Ref to, CellUsageTree *us return {}; } auto res = generate_raw(std::move(from), std::move(to), usage_tree); + if (res.first.is_null() || res.second.is_null()) { + return {}; + } return CellBuilder::create_merkle_update(res.first, res.second); } diff --git a/validator/impl/accept-block.cpp b/validator/impl/accept-block.cpp index ff953b66..cda1c787 100644 --- a/validator/impl/accept-block.cpp +++ b/validator/impl/accept-block.cpp @@ -225,6 +225,9 @@ bool AcceptBlockQuery::create_new_proof() { } // 5. finish constructing Merkle proof from visited cells auto proof = vm::MerkleProof::generate(block_root_, usage_tree.get()); + if (proof.is_null()) { + return fatal_error("cannot create proof"); + } proof_roots_.push_back(proof); // 6. extract some information from state update state_old_hash_ = upd_cs.prefetch_ref(0)->get_hash(0).bits(); diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index 8eab9103..83bc710c 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -2274,7 +2274,7 @@ td::Result> Collator::impl_crea 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->action_phase->state_size_too_big) && + if (trans->bounce_enabled && (!trans->compute_phase->success || trans->action_phase->state_exceeds_limits) && !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()); @@ -3640,6 +3640,9 @@ bool Collator::create_shard_state() { } LOG(INFO) << "creating Merkle update for the ShardState"; state_update = vm::MerkleUpdate::generate(prev_state_root_, state_root, state_usage_tree_.get()); + if (state_update.is_null()) { + return fatal_error("cannot create Merkle update for ShardState"); + } if (verbosity > 2) { std::cerr << "Merkle Update for ShardState: "; vm::CellSlice cs{vm::NoVm{}, state_update}; diff --git a/validator/impl/liteserver.cpp b/validator/impl/liteserver.cpp index 1e8bb820..66e73d8e 100644 --- a/validator/impl/liteserver.cpp +++ b/validator/impl/liteserver.cpp @@ -1168,7 +1168,7 @@ void LiteQuery::continue_getAccountState() { void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) { LOG(INFO) << "completing getAccountState() query"; - Ref proof1; + Ref proof1, proof2; if (!make_state_root_proof(proof1)) { return; } @@ -1197,7 +1197,11 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) { if (acc_csr.not_null()) { acc_root = acc_csr->prefetch_ref(); } - auto proof = vm::std_boc_serialize_multi({std::move(proof1), pb.extract_proof()}); + if (!pb.extract_proof_to(proof2)) { + fatal_error("unknown error creating Merkle proof"); + return; + } + auto proof = vm::std_boc_serialize_multi({std::move(proof1), std::move(proof2)}); pb.clear(); if (proof.is_error()) { fatal_error(proof.move_as_error()); @@ -1221,7 +1225,10 @@ void LiteQuery::finish_getAccountState(td::BufferSlice shard_proof) { fatal_error(S.move_as_error_prefix("Failed to load account: ")); return; } - acc_root = mpb.extract_proof(); + if (!mpb.extract_proof_to(acc_root)) { + fatal_error("unknown error creating Merkle proof"); + return; + } } auto res = vm::std_boc_serialize(std::move(acc_root)); if (res.is_error()) { @@ -1283,10 +1290,20 @@ void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice balance.validate_unpack(store.balance) && store.state->prefetch_ulong(1) == 1 && store.state.write().advance(1) && tlb::csr_unpack(std::move(store.state), state_init))) { LOG(INFO) << "error unpacking account state, or account is frozen or uninitialized"; + td::Result proof_boc; + if (mode & 2) { + proof_boc = pb.extract_proof_boc(); + if (proof_boc.is_error()) { + fatal_error(proof_boc.move_as_error()); + return; + } + } else { + proof_boc = td::BufferSlice(); + } auto b = ton::create_serialize_tl_object( mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof), - std::move(state_proof), mode & 2 ? pb.extract_proof_boc().move_as_ok() : td::BufferSlice(), td::BufferSlice(), - td::BufferSlice(), -0x100, td::BufferSlice()); + std::move(state_proof), proof_boc.move_as_ok(), td::BufferSlice(), td::BufferSlice(), -0x100, + td::BufferSlice()); finish_query(std::move(b)); return; } @@ -1340,10 +1357,20 @@ void LiteQuery::finish_runSmcMethod(td::BufferSlice shard_proof, td::BufferSlice } result = res.move_as_ok(); } + td::Result proof_boc; + if (mode & 2) { + proof_boc = pb.extract_proof_boc(); + if (proof_boc.is_error()) { + fatal_error(proof_boc.move_as_error()); + return; + } + } else { + proof_boc = td::BufferSlice(); + } auto b = ton::create_serialize_tl_object( mode, ton::create_tl_lite_block_id(base_blk_id_), ton::create_tl_lite_block_id(blk_id_), std::move(shard_proof), - std::move(state_proof), mode & 2 ? pb.extract_proof_boc().move_as_ok() : td::BufferSlice(), std::move(c7_info), - td::BufferSlice(), exit_code, std::move(result)); + std::move(state_proof), proof_boc.move_as_ok(), std::move(c7_info), td::BufferSlice(), exit_code, + std::move(result)); finish_query(std::move(b)); } diff --git a/validator/impl/validate-query.cpp b/validator/impl/validate-query.cpp index 50a3e591..7d8104e0 100644 --- a/validator/impl/validate-query.cpp +++ b/validator/impl/validate-query.cpp @@ -4506,7 +4506,7 @@ 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->action_phase->state_size_too_big) && + if (trs->bounce_enabled && (!trs->compute_phase->success || trs->action_phase->state_exceeds_limits) && !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());