#pragma once #include "interfaces/validator-manager.h" #include "vm/cells.h" #include "vm/dict.h" #include "block/mc-config.h" #include "block/transaction.h" #include "shard.hpp" #include "signature-set.hpp" #include #include #include #include "common/global-version.h" #include "tonlib/tonlib/ExtClient.h" namespace solution { using namespace ton; using namespace ton::validator; using td::Ref; class ErrorCtxAdd; class ErrorCtxSet; struct ErrorCtx { protected: friend class ErrorCtxAdd; friend class ErrorCtxSet; std::vector entries_; public: ErrorCtx() = default; ErrorCtx(std::vector str_list) : entries_(std::move(str_list)) { } ErrorCtx(std::string str) : entries_{str} { } std::string as_string() const; ErrorCtxAdd add_guard(std::string str_add); ErrorCtxSet set_guard(std::string str); ErrorCtxSet set_guard(std::vector str_list); }; class ErrorCtxAdd { ErrorCtx& ctx_; public: ErrorCtxAdd(ErrorCtx& ctx, std::string ctx_elem) : ctx_(ctx) { ctx_.entries_.push_back(std::move(ctx_elem)); } ~ErrorCtxAdd() { ctx_.entries_.pop_back(); } }; class ErrorCtxSet { ErrorCtx& ctx_; std::vector old_ctx_; public: ErrorCtxSet(ErrorCtx& ctx, std::vector new_ctx) : ctx_(ctx) { old_ctx_ = std::move(ctx_.entries_); ctx_.entries_ = std::move(new_ctx); } ErrorCtxSet(ErrorCtx& ctx, std::string new_ctx) : ErrorCtxSet(ctx, std::vector{new_ctx}) { } ~ErrorCtxSet() { ctx_.entries_ = std::move(old_ctx_); } }; inline ErrorCtxAdd ErrorCtx::add_guard(std::string str) { return ErrorCtxAdd(*this, std::move(str)); } inline ErrorCtxSet ErrorCtx::set_guard(std::string str) { return ErrorCtxSet(*this, std::move(str)); } inline ErrorCtxSet ErrorCtx::set_guard(std::vector str_list) { return ErrorCtxSet(*this, std::move(str_list)); } class ContestValidateQuery : public td::actor::Actor { static constexpr int supported_version() { return SUPPORTED_VERSION; } static constexpr long long supported_capabilities() { return ton::capCreateStatsEnabled | ton::capBounceMsgBody | ton::capReportVersion | ton::capShortDequeue | ton::capStoreOutMsgQueueSize | ton::capMsgMetadata | ton::capDeferMessages | ton::capFullCollatedData; } public: ContestValidateQuery(BlockIdExt block_id, td::BufferSlice block_data, td::BufferSlice collated_data, td::Promise promise); private: int verbosity{0}; int pending{0}; const ShardIdFull shard_; const BlockIdExt id_; std::vector prev_blocks; std::vector> prev_states; td::BufferSlice block_data, collated_data; td::Promise main_promise; bool after_merge_{false}; bool after_split_{false}; bool before_split_{false}; bool want_split_{false}; bool want_merge_{false}; bool is_key_block_{false}; bool update_shard_cc_{false}; bool prev_key_block_exists_{false}; bool debug_checks_{false}; bool outq_cleanup_partial_{false}; BlockSeqno prev_key_seqno_{~0u}; int stage_{0}; td::BitArray<64> shard_pfx_; int shard_pfx_len_; td::Bits256 created_by_; Ref prev_state_root_; std::shared_ptr state_usage_tree_; // used to construct Merkle update ErrorCtx error_ctx_; td::Ref mc_state_; td::Ref mc_state_root_; BlockIdExt mc_blkid_; ton::BlockSeqno mc_seqno_{0}; Ref block_root_; std::vector> collated_roots_; std::map> virt_roots_; std::unique_ptr top_shard_descr_dict_; block::gen::ExtraCollatedData::Record extra_collated_data_; bool have_extra_collated_data_ = false; Ref recover_create_msg_, mint_msg_; // from McBlockExtra (UNCHECKED) std::unique_ptr config_; std::unique_ptr old_shard_conf_; // from reference mc state std::unique_ptr new_shard_conf_; // from shard_hashes_ in mc blocks Ref wc_info_; Ref old_mparams_; bool accept_msgs_{true}; ton::BlockSeqno min_shard_ref_mc_seqno_{~0U}; ton::LogicalTime max_shard_lt_{0}; int global_id_{0}; ton::BlockSeqno vert_seqno_{~0U}; bool ihr_enabled_{false}; bool create_stats_enabled_{false}; ton::BlockSeqno prev_key_block_seqno_; ton::BlockIdExt prev_key_block_; ton::LogicalTime prev_key_block_lt_; std::unique_ptr block_limits_; std::unique_ptr block_limit_status_; td::uint64 total_gas_used_{0}, total_special_gas_used_{0}; LogicalTime start_lt_, end_lt_; UnixTime now_{~0u}; ton::Bits256 rand_seed_; std::vector storage_prices_; block::StoragePhaseConfig storage_phase_cfg_{&storage_prices_}; block::ComputePhaseConfig compute_phase_cfg_; block::ActionPhaseConfig action_phase_cfg_; td::RefInt256 masterchain_create_fee_, basechain_create_fee_; std::vector neighbors_; std::map> aux_mc_states_; block::ShardState ps_; block::ShardState ns_; bool processed_upto_updated_{false}; std::unique_ptr sibling_out_msg_queue_; std::shared_ptr sibling_processed_upto_; std::map block_create_count_; unsigned block_create_total_{0}; std::unique_ptr in_msg_dict_, out_msg_dict_, account_blocks_dict_; block::ValueFlow value_flow_; block::CurrencyCollection import_created_, transaction_fees_, total_burned_{0}, fees_burned_{0}; td::RefInt256 import_fees_; ton::LogicalTime proc_lt_{0}, claimed_proc_lt_{0}, min_enq_lt_{~0ULL}; ton::Bits256 proc_hash_ = ton::Bits256::zero(), claimed_proc_hash_, min_enq_hash_; std::vector> msg_proc_lt_; std::vector> msg_emitted_lt_; std::map, Ref> removed_dispatch_queue_messages_; std::map, Ref> new_dispatch_queue_messages_; std::set account_expected_defer_all_messages_; td::uint64 old_out_msg_queue_size_ = 0; bool out_msg_queue_size_known_ = false; bool have_out_msg_queue_size_in_state_ = false; bool msg_metadata_enabled_ = false; bool deferring_messages_enabled_ = false; bool store_out_msg_queue_size_ = false; td::uint64 processed_account_dispatch_queues_ = 0; bool have_unprocessed_account_dispatch_queue_ = false; WorkchainId workchain() const { return shard_.workchain; } void finish_query(); void abort_query(td::Status error); bool reject_query(std::string error, td::BufferSlice reason = {}); bool reject_query(std::string err_msg, td::Status error, td::BufferSlice reason = {}); bool soft_reject_query(std::string error, td::BufferSlice reason = {}); void start_up() override; bool fatal_error(td::Status error); bool fatal_error(int err_code, std::string err_msg); bool fatal_error(int err_code, std::string err_msg, td::Status error); bool fatal_error(std::string err_msg, int err_code = -666); std::string error_ctx() const { return error_ctx_.as_string(); } ErrorCtxAdd error_ctx_add_guard(std::string str) { return error_ctx_.add_guard(std::move(str)); } ErrorCtxSet error_ctx_set_guard(std::string str) { return error_ctx_.set_guard(std::move(str)); } td::actor::ActorId get_self() { return actor_id(this); } td::Result> fetch_block_state(BlockIdExt block_id) { Ref state_root = get_virt_state_root(block_id.root_hash); if (state_root.is_null()) { return td::Status::Error(PSTRING() << "cannot get hash of state root: " << block_id.to_str()); } td::Bits256 state_root_hash = state_root->get_hash().bits(); auto it = virt_roots_.find(state_root_hash); if (it == virt_roots_.end()) { return td::Status::Error(PSTRING() << "cannot get state root from collated data: " << block_id.to_str()); } TRY_RESULT(res, ShardStateQ::fetch(block_id, {}, it->second)); return Ref(res); } void after_get_mc_state(td::Result> res); void after_get_shard_state(int idx, td::Result> res); bool process_mc_state(Ref mc_state); bool try_unpack_mc_state(); bool fetch_config_params(); bool check_prev_block(const BlockIdExt& listed, const BlockIdExt& prev, bool chk_chain_len = true); bool check_prev_block_exact(const BlockIdExt& listed, const BlockIdExt& prev); bool check_this_shard_mc_info(); bool init_parse(); bool unpack_block_candidate(); bool extract_collated_data_from(Ref croot, int idx); bool extract_collated_data(); bool try_validate(); bool compute_prev_state(); bool unpack_merge_prev_state(); bool unpack_prev_state(); bool init_next_state(); bool unpack_one_prev_state(block::ShardState& ss, BlockIdExt blkid, Ref prev_state_root); bool split_prev_state(block::ShardState& ss); bool request_neighbor_queues(); void got_neighbor_out_queue(int i, td::Result> res); bool register_mc_state(Ref other_mc_state); bool request_aux_mc_state(BlockSeqno seqno, Ref& state); Ref get_aux_mc_state(BlockSeqno seqno) const; void after_get_aux_shard_state(ton::BlockIdExt blkid, td::Result> res); bool check_utime_lt(); bool prepare_out_msg_queue_size(); void got_out_queue_size(size_t i, td::Result res); bool fix_one_processed_upto(block::MsgProcessedUpto& proc, ton::ShardIdFull owner, bool allow_cur = false); bool fix_processed_upto(block::MsgProcessedUptoCollection& upto, bool allow_cur = false); bool fix_all_processed_upto(); bool add_trivial_neighbor_after_merge(); bool add_trivial_neighbor(); bool unpack_block_data(); bool unpack_precheck_value_flow(Ref value_flow_root); bool compute_minted_amount(block::CurrencyCollection& to_mint); bool postcheck_one_account_update(td::ConstBitPtr acc_id, Ref old_value, Ref new_value); bool postcheck_account_updates(); bool precheck_one_transaction(td::ConstBitPtr acc_id, ton::LogicalTime trans_lt, Ref trans_csr, ton::Bits256& prev_trans_hash, ton::LogicalTime& prev_trans_lt, unsigned& prev_trans_lt_len, ton::Bits256& acc_state_hash); bool precheck_one_account_block(td::ConstBitPtr acc_id, Ref acc_blk); bool precheck_account_transactions(); Ref lookup_transaction(const ton::StdSmcAddress& addr, ton::LogicalTime lt) const; bool is_valid_transaction_ref(Ref trans_ref) const; bool build_new_message_queue(); bool precheck_one_message_queue_update(td::ConstBitPtr out_msg_id, Ref old_value, Ref new_value); bool precheck_message_queue_update(); bool check_account_dispatch_queue_update(td::Bits256 addr, Ref old_queue_csr, Ref new_queue_csr); bool unpack_dispatch_queue_update(); bool update_max_processed_lt_hash(ton::LogicalTime lt, const ton::Bits256& hash); bool update_min_enqueued_lt_hash(ton::LogicalTime lt, const ton::Bits256& hash); bool check_imported_message(Ref msg_env); bool is_special_in_msg(const vm::CellSlice& in_msg) const; bool check_in_msg(td::ConstBitPtr key, Ref in_msg); bool check_in_msg_descr(); bool check_out_msg(td::ConstBitPtr key, Ref out_msg); bool check_out_msg_descr(); bool check_dispatch_queue_update(); bool check_processed_upto(); bool check_neighbor_outbound_message(Ref enq_msg, ton::LogicalTime lt, td::ConstBitPtr key, const block::McShardDescr& src_nb, bool& unprocessed, bool& processed_here, td::Bits256& msg_hash); bool check_in_queue(); std::unique_ptr make_account_from(td::ConstBitPtr addr, Ref account); std::unique_ptr unpack_account(td::ConstBitPtr addr); bool check_one_transaction(block::Account& account, LogicalTime lt, Ref trans_root, bool is_first, bool is_last); bool check_account_transactions(const StdSmcAddress& acc_addr, Ref acc_tr); bool check_transactions(); bool check_message_processing_order(); bool check_new_state(); bool postcheck_value_flow(); Ref get_virt_state_root(td::Bits256 block_root_hash); td::BufferSlice result_state_update_; bool store_master_ref(vm::CellBuilder& cb); bool build_state_update(); }; } // namespace solution