/* 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 #include #include #include "catchain-types.h" #include "catchain-receiver.h" #include "catchain-receiver-source.h" #include "catchain-received-block.h" #include "td/db/KeyValueAsync.h" namespace ton { namespace catchain { class CatChainReceiverImpl final : public CatChainReceiver { public: PrintId print_id() const override { return PrintId{incarnation_, local_id_}; } CatChainSessionId get_incarnation() const override { return incarnation_; } void run_block(CatChainReceivedBlock *block) override; td::uint32 get_forks_cnt() const override { return total_forks_; } td::uint32 get_sources_cnt() const override { return static_cast(sources_.size()); } CatChainReceiverSource *get_source(td::uint32 source_id) const override { if (source_id >= get_sources_cnt()) { return nullptr; } return sources_[source_id].get(); } PublicKeyHash get_source_hash(td::uint32 source_id) const override; CatChainReceiverSource *get_source_by_hash(const PublicKeyHash &source_hash) const; CatChainReceiverSource *get_source_by_adnl_id(adnl::AdnlNodeIdShort source_hash) const; td::uint32 add_fork() override; void deliver_block(CatChainReceivedBlock *block) override; void receive_message_from_overlay(adnl::AdnlNodeIdShort src, td::BufferSlice data); void receive_query_from_overlay(adnl::AdnlNodeIdShort src, td::BufferSlice data, td::Promise promise); void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getBlock query, td::Promise promise); void process_query(adnl::AdnlNodeIdShort src, ton_api::catchain_getDifference query, td::Promise promise); template void process_query(adnl::AdnlNodeIdShort src, const T &query, td::Promise promise) { callback_->on_custom_query(get_source_by_adnl_id(src)->get_hash(), serialize_tl_object(&query, true), std::move(promise)); } void receive_broadcast_from_overlay(const PublicKeyHash &src, td::BufferSlice data); void receive_block(adnl::AdnlNodeIdShort src, tl_object_ptr block, td::BufferSlice payload); void receive_block_answer(adnl::AdnlNodeIdShort src, td::BufferSlice); CatChainReceivedBlock *create_block(tl_object_ptr block, td::SharedSlice payload) override; CatChainReceivedBlock *create_block(tl_object_ptr block) override; td::Status validate_block_sync(const tl_object_ptr &dep) const override; td::Status validate_block_sync(const tl_object_ptr &block, const td::Slice &payload) const override; void send_fec_broadcast(td::BufferSlice data) override; void send_custom_query_data(const PublicKeyHash &dst, std::string name, td::Promise promise, td::Timestamp timeout, td::BufferSlice query) override; void send_custom_query_data_via(const PublicKeyHash &dst, std::string name, td::Promise promise, td::Timestamp timeout, td::BufferSlice query, td::uint64 max_answer_size, td::actor::ActorId via) override; void send_custom_message_data(const PublicKeyHash &dst, td::BufferSlice query) override; void run_scheduler(); void add_block(td::BufferSlice data, std::vector deps) override; void add_block_cont(tl_object_ptr block, td::BufferSlice payload); void add_block_cont_2(tl_object_ptr block, td::BufferSlice payload); void add_block_cont_3(tl_object_ptr block, td::BufferSlice payload); void debug_add_fork(td::BufferSlice payload, CatChainBlockHeight height, std::vector deps) override; void debug_add_fork_cont(tl_object_ptr block, td::BufferSlice payload); void on_blame(td::uint32 src) override { callback_->blame(src); } void on_found_fork_proof(td::uint32 source_id, td::BufferSlice data) override; void on_blame_processed(td::uint32 source_id) override; const CatChainOptions &opts() const override { return opts_; } void got_fork_proof(td::BufferSlice data); void synchronize_with(CatChainReceiverSource *source); void alarm() override; void start_up() override; void tear_down() override; void read_db(); void read_db_from(CatChainBlockHash id); void read_block_from_db(CatChainBlockHash id, td::BufferSlice data); void block_written_to_db(CatChainBlockHash hash); bool unsafe_start_up_check_completed(); void written_unsafe_root_block(CatChainReceivedBlock *block); void destroy() override; CatChainReceivedBlock *get_block(CatChainBlockHash hash) const; CatChainReceiverImpl(std::unique_ptr callback, const CatChainOptions &opts, td::actor::ActorId keyring, td::actor::ActorId adnl, td::actor::ActorId overlays, const std::vector &ids, const PublicKeyHash &local_id, const CatChainBlockHash &unique_hash, std::string db_root, std::string db_suffix, bool allow_unsafe_self_blocks_resync); private: std::unique_ptr make_callback() { class Callback : public overlay::Overlays::Callback { public: void receive_message(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override { td::actor::send_closure(id_, &CatChainReceiverImpl::receive_message_from_overlay, src, std::move(data)); } void receive_query(adnl::AdnlNodeIdShort src, overlay::OverlayIdShort overlay_id, td::BufferSlice data, td::Promise promise) override { td::actor::send_closure(id_, &CatChainReceiverImpl::receive_query_from_overlay, src, std::move(data), std::move(promise)); } void receive_broadcast(PublicKeyHash src, overlay::OverlayIdShort overlay_id, td::BufferSlice data) override { td::actor::send_closure(id_, &CatChainReceiverImpl::receive_broadcast_from_overlay, src, std::move(data)); } explicit Callback(td::actor::ActorId id) : id_(std::move(id)) { } private: td::actor::ActorId id_; }; return std::make_unique(actor_id(this)); } struct PendingBlock { td::BufferSlice payload_; std::vector deps_; PendingBlock(td::BufferSlice &&payload, std::vector &&deps) : payload_(std::move(payload)), deps_(std::move(deps)) { } }; std::list> pending_blocks_; bool active_send_ = false; bool read_db_ = false; td::uint32 pending_in_db_ = 0; CatChainBlockHash db_root_block_ = CatChainBlockHash::zero(); void choose_neighbours(); std::vector> sources_; std::map sources_hashes_; std::map sources_adnl_addrs_; td::uint32 total_forks_ = 0; std::map> blocks_; CatChainReceivedBlock *root_block_; CatChainReceivedBlock *last_sent_block_; CatChainSessionId incarnation_{}; std::unique_ptr callback_; CatChainOptions opts_; std::vector neighbours_; td::actor::ActorId keyring_; td::actor::ActorId adnl_; td::actor::ActorId overlay_manager_; overlay::OverlayIdShort overlay_id_; overlay::OverlayIdFull overlay_full_id_; PublicKeyHash local_id_; td::uint32 local_idx_; td::Timestamp next_sync_; td::Timestamp next_rotate_; std::string db_root_; std::string db_suffix_; using DbType = td::KeyValueAsync; DbType db_; bool intentional_fork_ = false; td::Timestamp initial_sync_complete_at_{td::Timestamp::never()}; bool allow_unsafe_self_blocks_resync_{false}; bool unsafe_root_block_writing_{false}; bool started_{false}; std::list to_run_; std::vector blame_processed_; std::map pending_fork_proofs_; }; } // namespace catchain } // namespace ton namespace td { inline td::StringBuilder &operator<<(td::StringBuilder &sb, const ton::catchain::CatChainReceiverImpl *catchain) { sb << catchain->print_id(); return sb; } } // namespace td