/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2020 Telegram Systems LLP */ #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" namespace ton { namespace 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)); } /* * * must write candidate to disk, if accepted * can reject block only if it is invalid (i.e. in case of * internal errors must retry or crash) * only exception: block can be rejected, if it is known from * masterchain, that it will not be part of shardchain finalized * state * */ class ValidateQuery : 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; } public: ValidateQuery(ShardIdFull shard, BlockIdExt min_masterchain_block_id, std::vector prev, BlockCandidate candidate, td::Ref validator_set, td::actor::ActorId manager, td::Timestamp timeout, td::Promise promise, bool is_fake = false); private: int verbosity{3 * 1}; int pending{0}; const ShardIdFull shard_; const BlockIdExt id_; BlockIdExt min_mc_block_id; std::vector prev_blocks; std::vector> prev_states; BlockCandidate block_candidate; td::Ref validator_set_; td::actor::ActorId manager; td::Timestamp timeout; 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 is_fake_{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_; Ref state_root_; Ref state_update_; ton::Bits256 prev_state_hash_, state_hash_; ErrorCtx error_ctx_; td::Ref mc_state_, latest_mc_state_; td::Ref mc_state_root_; BlockIdExt mc_blkid_, latest_mc_blkid_; ton::BlockSeqno mc_seqno_{0}, latest_mc_seqno_; Ref block_root_; std::vector> collated_roots_; std::map> virt_roots_; std::unique_ptr top_shard_descr_dict_; Ref shard_hashes_; // from McBlockExtra Ref blk_config_params_; // from McBlockExtra Ref prev_signatures_; // from McBlockExtra (UNCHECKED) Ref recover_create_msg_, mint_msg_; // from McBlockExtra (UNCHECKED) std::unique_ptr config_, new_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_; std::unique_ptr fees_import_dict_; Ref old_mparams_; bool accept_msgs_{true}; ton::BlockSeqno min_shard_ref_mc_seqno_{~0U}; ton::UnixTime max_shard_utime_{0}; 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 prev_now_{~0u}, 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_, ns_; 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::vector> lib_publishers_, lib_publishers2_; 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, new_out_msg_queue_size_ = 0; 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; td::PerfWarningTimer perf_timer_; static constexpr td::uint32 priority() { return 2; } 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 alarm() override; void start_up() override; bool save_candidate(); void written_candidate(); 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)); } bool is_masterchain() const { return shard_.is_masterchain(); } td::actor::ActorId get_self() { return actor_id(this); } void request_latest_mc_state(); void after_get_latest_mc_state(td::Result, BlockIdExt>> res); void after_get_mc_state(td::Result> res); void got_mc_handle(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 compute_next_state(); bool unpack_merge_prev_state(); bool unpack_prev_state(); bool unpack_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_one_shard(const block::McShardHash& info, const block::McShardHash* sibling, const block::WorkchainInfo* wc_info, const block::CatchainValidatorsConfig& ccvc); bool check_shard_layout(); bool register_shard_block_creators(std::vector creator_list); bool check_cur_validator_set(); bool check_mc_validator_info(bool update_mc_cc); 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 precheck_one_account_update(td::ConstBitPtr acc_id, Ref old_value, Ref new_value); bool precheck_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 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 check_in_queue(); bool check_delivered_dequeued(); 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 scan_account_libraries(Ref orig_libs, Ref final_libs, const td::Bits256& addr); bool check_all_ticktock_processed(); bool check_message_processing_order(); bool check_special_message(Ref in_msg_root, const block::CurrencyCollection& amount, Ref addr_cell); bool check_special_messages(); bool check_one_library_update(td::ConstBitPtr key, Ref old_value, Ref new_value); bool check_shard_libraries(); bool check_new_state(); bool check_config_update(Ref old_conf_params, Ref new_conf_params); bool check_one_prev_dict_update(ton::BlockSeqno seqno, Ref old_val_extra, Ref new_val_extra); bool check_mc_state_extra(); bool postcheck_value_flow(); td::Status check_counter_update(const block::DiscountedCounter& oc, const block::DiscountedCounter& nc, unsigned expected_incr); bool check_one_block_creator_update(td::ConstBitPtr key, Ref old_val, Ref new_val); bool check_block_create_stats(); 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; } td::Timer work_timer_{true}; td::ThreadCpuTimer cpu_work_timer_{true}; void record_stats(); }; } // namespace validator } // namespace ton