text: // Copyright (c) 2014-2020 The Virie Project
  // Copyright (c) 2012-2013 The Cryptonote developers
  // Copyright (c) 2012-2013 The Boolberry developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #include "include_base_utils.h"
  using namespace epee;
  
  #include <boost/foreach.hpp>
  #include <unordered_set>
  #include "currency_core.h"
  #include "common/command_line.h"
  #include "common/util.h"
  #include "warnings.h"
  #include "crypto/crypto.h"
  #include "currency_core/currency_config.h"
  #include "currency_format_utils.h"
  #include "misc_language.h"
  #include "tx_validation.h"
  
  DISABLE_VS_WARNINGS(4355)
  #undef LOG_DEFAULT_CHANNEL 
  #define LOG_DEFAULT_CHANNEL "core"
  ENABLE_CHANNEL_BY_DEFAULT("core", "Currency core default channel.")
  namespace currency
  {
  
    //-----------------------------------------------------------------------------------------------
    core::core(i_currency_protocol* pprotocol):
                m_blockchain_storage(m_mempool),
                m_mempool(m_blockchain_storage, pprotocol),
                m_stop_handler(nullptr),
                m_miner(this),
                m_miner_address(boost::value_initialized<account_public_address>()),
                m_starter_message_showed(false)
    {
      set_currency_protocol(pprotocol);
    }
    void core::set_currency_protocol(i_currency_protocol* pprotocol)
    {
      if(pprotocol)
        m_pprotocol = pprotocol;
      else
        m_pprotocol = &m_protocol_stub;
  
      m_mempool.set_protocol(m_pprotocol);
    }
    //-----------------------------------------------------------------------------------
    void core::set_stop_handler(i_stop_handler *handler)
    {
      m_stop_senders.set_stop_handler(handler);
    }
    //-----------------------------------------------------------------------------------
    bool core::set_checkpoints(checkpoints&& chk_pts)
    {
      return m_blockchain_storage.set_checkpoints(std::forward<checkpoints>(chk_pts));
    }
    //-----------------------------------------------------------------------------------
    void core::validate_checkpoints()
    {
      uint64_t valid_blockchain_size;
      if (!m_blockchain_storage.validate_checkpoints(valid_blockchain_size))
      {
        LOG_ERROR("failed to validate checkpoints");
        m_blockchain_storage.truncate_blockchain(valid_blockchain_size);
      }
    }
    //-----------------------------------------------------------------------------------
    void core::init_options(boost::program_options::options_description& desc)
    {
      blockchain_storage::init_options(desc);
    }
    //-----------------------------------------------------------------------------------------------
    std::string core::get_config_folder()
    {
      return m_config_folder;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::handle_command_line(const boost::program_options::variables_map& vm)
    {
      m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir);
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    uint64_t core::get_current_blockchain_size() const
    {
      return m_blockchain_storage.get_current_blockchain_size();
    }
    //-----------------------------------------------------------------------------------------------
    uint64_t core::get_top_block_height() const
    {
      return m_blockchain_storage.get_top_block_height();
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) const
    {
      top_id = m_blockchain_storage.get_top_block_id(height);
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks, std::list<transaction>& txs)
    {
      return m_blockchain_storage.get_blocks(start_offset, count, blocks, txs);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks)
    {
      return m_blockchain_storage.get_blocks(start_offset, count, blocks);
    }  //-----------------------------------------------------------------------------------------------
    bool core::get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<transaction>& txs, std::list<crypto::hash>& missed_txs)
    {
      return m_blockchain_storage.get_transactions(txs_ids, txs, missed_txs);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_transaction(const crypto::hash &h, transaction &tx)
    {
      std::vector<crypto::hash> ids;
      ids.push_back(h);
      std::list<transaction> ltx;
      std::list<crypto::hash> missing;
      if (m_blockchain_storage.get_transactions(ids, ltx, missing))
      {
        if (ltx.size() > 0)
        {
          tx = *ltx.begin();
          return true;
        }
      }
  
      return false;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_alternative_blocks(std::list<block>& blocks)
    {
      return m_blockchain_storage.get_alternative_blocks(blocks);
    }
    //-----------------------------------------------------------------------------------------------
    size_t core::get_alternative_blocks_count()
    {
      return m_blockchain_storage.get_alternative_blocks_count();
    }
    //-----------------------------------------------------------------------------------------------
    bool core::init(const boost::program_options::variables_map& vm)
    {
      bool r = handle_command_line(vm);
  
      r = m_mempool.init(m_config_folder);
      CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
  
      r = m_blockchain_storage.init(m_config_folder, vm);
      CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
  
      r = m_miner.init(vm);
      CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner");
  
      //check if tx_pool module synchronized with blockchaine storage
  //     if (m_blockchain_storage.get_top_block_id() != m_mempool.get_last_core_hash())
  //     {
  //       m_mempool.clear();
  //       LOG_PRINT_MAGENTA("Tx pool had been reset due to missmatch top block id", LOG_LEVEL_0);
  //     }
  
      r = load_state_data();
      CHECK_AND_ASSERT_MES(r, false, "Failed to load state data");
  
      validate_checkpoints();
  
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::set_genesis_block(const block& b)
    {
      return m_blockchain_storage.reset_and_set_genesis_block(b);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::load_state_data()
    {
      // may be some code later
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::deinit()
    {
      //m_mempool.set_last_core_hash(m_blockchain_storage.get_top_block_id());
  
      m_miner.stop();
      m_miner.deinit();
      m_mempool.deinit();
      m_blockchain_storage.deinit();
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool kept_by_block)
    {
      tvc = boost::value_initialized<tx_verification_context>();
      //want to process all transactions sequentially
      TIME_MEASURE_START_MS(wait_lock_time);
      CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
      TIME_MEASURE_FINISH_MS(wait_lock_time);
  
      if(tx_blob.size() > get_max_tx_size())
      {
        LOG_PRINT_L0("WRONG TRANSACTION BLOB, too big size " << tx_blob.size() << ", rejected");
        tvc.m_verification_failed = true;
        return false;
      }
  
      if(tx_blob.size() >= m_blockchain_storage.get_current_comulative_blocksize_limit() - CURRENCY_COINBASE_BLOB_RESERVED_SIZE)
      {
        LOG_PRINT_RED_L0("tx has too big size " << tx_blob.size() << ", expected no bigger than " << m_blockchain_storage.get_current_comulative_blocksize_limit() - CURRENCY_COINBASE_BLOB_RESERVED_SIZE);
        tvc.m_verification_failed = true;
        return false;
      }
  
      crypto::hash tx_hash = null_hash;
      transaction tx;
      TIME_MEASURE_START_MS(parse_tx_time);
      if(!parse_tx_from_blob(tx, tx_hash, tx_blob))
      {
        LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to parse, rejected");
        tvc.m_verification_failed = true;
        return false;
      }
      TIME_MEASURE_FINISH_MS(parse_tx_time);
      
  
      TIME_MEASURE_START_MS(check_tx_syntax_time);
      if(!check_tx_syntax(tx))
      {
        LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected");
        tvc.m_verification_failed = true;
        return false;
      }
      TIME_MEASURE_FINISH_MS(check_tx_syntax_time);
  
      TIME_MEASURE_START_MS(check_tx_semantic_time);
      if(!check_tx_semantic(tx))
      {
        LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
        tvc.m_verification_failed = true;
        return false;
      }
      TIME_MEASURE_FINISH_MS(check_tx_semantic_time);
  
      TIME_MEASURE_START_MS(add_new_tx_time);
      bool r = add_new_tx(tx, tx_hash, get_object_blobsize(tx), tvc, kept_by_block);
      TIME_MEASURE_FINISH_MS(add_new_tx_time);
  
      if(tvc.m_verification_failed)
      {LOG_PRINT_RED_L0("Transaction verification failed: " << tx_hash);}
      else if(tvc.m_verification_impossible)
      {LOG_PRINT_RED_L0("Transaction verification impossible: " << tx_hash);}
  
      if (tvc.m_added_to_pool)
      {
        LOG_PRINT_L2("incoming tx " << tx_hash << " was added to the pool");
      }
      LOG_PRINT_L2("[CORE HANDLE_INCOMING_TX]: timing " << wait_lock_time
        << "/" << parse_tx_time
        << "/" << check_tx_syntax_time
        << "/" << check_tx_semantic_time
        << "/" << add_new_tx_time);
      return r;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_stat_info(const core_stat_info::params& pr, core_stat_info& st_inf)
    {
      st_inf.mining_speed = m_miner.get_speed();
      st_inf.alternative_blocks = m_blockchain_storage.get_alternative_blocks_count();
      st_inf.blockchain_height = m_blockchain_storage.get_current_blockchain_size();
      st_inf.tx_pool_size = m_mempool.get_transactions_count();
      st_inf.top_block_id_str = epee::string_tools::pod_to_hex(m_blockchain_storage.get_top_block_id());
      
      std::list<block> blocks;
      m_blockchain_storage.get_blocks(m_blockchain_storage.get_current_blockchain_size() - pr.chain_len, static_cast<size_t>(pr.chain_len), blocks);
      for (auto& b : blocks)
      {
        st_inf.main_chain_blocks.push_back(chain_entry());
        st_inf.main_chain_blocks.back().h = get_block_height(b);
        st_inf.main_chain_blocks.back().id = epee::string_tools::pod_to_hex(get_block_hash(b));
      }
      blocks.clear();
      m_blockchain_storage.get_alternative_blocks(blocks);
      for (auto& b : blocks)
      {
        st_inf.alt_chain_blocks.push_back(chain_entry());
        st_inf.alt_chain_blocks.back().h = get_block_height(b);
        st_inf.alt_chain_blocks.back().id = epee::string_tools::pod_to_hex(get_block_hash(b));
      }
      blocks.clear();
  
      auto ch_locked_proxy_container = epee::log_space::get_channels_errors_stat_container();
      epee::log_space::channels_err_stat_container_type& ch_container_std = *ch_locked_proxy_container;
      for (const auto& entry : ch_container_std)
      {
        st_inf.errors_stat.push_back(error_stat_entry());
        st_inf.errors_stat.back().channel = entry.first;
        st_inf.errors_stat.back().err_count = entry.second;
      }
      st_inf.epic_failure_happend = m_blockchain_storage.get_performnce_data().epic_failure_happend;
      epee::log_space::log_singletone::get_journal_items(st_inf.errors_journal, pr.logs_journal_len);
      //check deadlocks
      auto dl_list = epee::deadlock_guard_singleton::get_deadlock_journal();
      if (dl_list.size())
      {
        st_inf.epic_failure_happend = true;
        st_inf.errors_journal.insert(st_inf.errors_journal.end(), dl_list.begin(), dl_list.end());
      }
  
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::add_new_tx(const transaction& tx, tx_verification_context& tvc, bool kept_by_block)
    {
      crypto::hash tx_hash = null_hash;
      uint64_t blob_size = 0;
      get_transaction_hash(tx, tx_hash, blob_size);
      return add_new_tx(tx, tx_hash, blob_size, tvc, kept_by_block);
    }
    //-----------------------------------------------------------------------------------------------
    size_t core::get_blockchain_total_transactions()
    {
      return m_blockchain_storage.get_total_transactions();
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_outs(uint64_t amount, std::list<crypto::public_key>& pkeys)
    {
      return m_blockchain_storage.get_outs(amount, pkeys);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, size_t blob_size, tx_verification_context& tvc, bool kept_by_block)
    {
      if(m_mempool.have_tx(tx_hash))
      {
        LOG_PRINT_L3("add_new_tx: already have tx " << tx_hash << " in the pool");
        return true;
      }
  
      if(m_blockchain_storage.have_tx(tx_hash))
      {
        LOG_PRINT_L3("add_new_tx: already have tx " << tx_hash << " in the blockchain");
        return true;
      }
      const uint64_t tx_min_fee = currency::get_tx_minimum_fee(get_current_blockchain_size());
      return m_mempool.add_tx(tx, tx_min_fee, tx_hash, blob_size, tvc, kept_by_block);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe)
    {
      return m_blockchain_storage.create_block_template(b, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_block_template(const create_block_template_params& params, create_block_template_response& resp)
    {
      return m_blockchain_storage.create_block_template(params, resp);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const 
    {
      return m_blockchain_storage.find_blockchain_supplement(qblock_ids, resp);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<block, std::list<transaction> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const 
    {
      return m_blockchain_storage.find_blockchain_supplement(qblock_ids, blocks, total_height, start_height, max_count);
    }
    //-----------------------------------------------------------------------------------------------
    void core::print_blockchain(std::ostream &s, uint64_t start_index, uint64_t end_index)
    {
      m_blockchain_storage.print_blockchain(s, start_index, end_index);
    }
    //-----------------------------------------------------------------------------------------------
    void core::print_blockchain_index()
    {
      m_blockchain_storage.print_blockchain_index();
    }
    //-----------------------------------------------------------------------------------------------
    void core::print_blockchain_outs(const std::string& file)
    {
      m_blockchain_storage.print_blockchain_outs(file);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)
    {
      return m_blockchain_storage.get_random_outs_for_amounts(req, res);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs)
    {
      return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, indexs);
    }
    //-----------------------------------------------------------------------------------------------
    void core::pause_mine()
    {
      m_miner.pause();
    }
    //-----------------------------------------------------------------------------------------------
    void core::resume_mine()
    {
      m_miner.resume();
    }
    //-----------------------------------------------------------------------------------------------
    bool core::handle_block_found(const block& b, block_verification_context* p_verification_result /* = nullptr */)
    {
      TIME_MEASURE_START_MS(time_total_ms);
      block_verification_context bvc = boost::value_initialized<block_verification_context>();
      if (!p_verification_result)
        p_verification_result = &bvc;
  
      m_miner.pause();
      misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([this]()
      {
        m_miner.resume();
      });
  
      TIME_MEASURE_START_MS(time_add_new_block_ms);
      m_blockchain_storage.add_new_block(b, *p_verification_result);
      TIME_MEASURE_FINISH_MS(time_add_new_block_ms);
  
  
      //anyway - update miner template
      TIME_MEASURE_START_MS(time_update_block_template_ms);
      update_miner_block_template();
      TIME_MEASURE_FINISH_MS(time_update_block_template_ms);
  
      uint64_t time_pack_txs_ms = 0, time_relay_ms = 0;
  
      if (p_verification_result->m_verification_failed || !p_verification_result->m_added_to_main_chain)
      {
        LOG_PRINT2("failed_mined_blocks.log", "verification_failed: " << p_verification_result->m_verification_failed << ", added_to_main_chain: " << p_verification_result->m_added_to_main_chain << ENDL <<
          currency::obj_to_json_str(b), LOG_LEVEL_0);
      }
      CHECK_AND_ASSERT_MES(!p_verification_result->m_verification_failed, false, "mined block has failed to pass verification: id " << get_block_hash(b) << " @ height " << get_block_height(b) << " prev_id: " << b.prev_id);
  
      if(p_verification_result->m_added_to_main_chain)
      {
        time_pack_txs_ms = epee::misc_utils::get_tick_count();
        currency_connection_context exclude_context = boost::value_initialized<currency_connection_context>();
        NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg);
        arg.hop = 0;
        arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_size();
        std::list<crypto::hash> missed_txs;
        std::list<transaction> txs;
        m_blockchain_storage.get_transactions(b.tx_hashes, txs, missed_txs);
        if(missed_txs.size() && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b))
        {
          LOG_PRINT_L0("Block found (id " << get_block_hash(b) << " @ height " << get_block_height(b) << ") but it seems that reorganize just happened after that, do not relay this block");
          return true;
        }
        if (txs.size() != b.tx_hashes.size() || missed_txs.size() != 0)
        {
          std::stringstream ss;
          ss << "txs:" << ENDL;
          for (auto& t : txs)
            ss << get_transaction_hash(t) << ENDL;
          ss << "missed txs:" << ENDL;
          for (auto& tx_id : missed_txs)
            ss << tx_id << ENDL;
          LOG_ERROR("can't find some transactions in found block: " << get_block_hash(b) << ", txs.size()=" << txs.size()
            << ", b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()=" << missed_txs.size() << ENDL << ss.str());
          return false;
        }
  
        block_to_blob(b, arg.b.block);
        //pack transactions
        for(auto& tx : txs)
          arg.b.txs.push_back(t_serializable_object_to_blob(tx));
  
        TIME_MEASURE_FINISH_MS(time_pack_txs_ms);
  
        time_relay_ms = epee::misc_utils::get_tick_count();
        m_pprotocol->relay_block(arg, exclude_context);
        TIME_MEASURE_FINISH_MS(time_relay_ms);
      }
  
      TIME_MEASURE_FINISH_MS(time_total_ms);
      LOG_PRINT_L2("handle_block_found timings (ms): total: " << time_total_ms << ", add new block: " << time_add_new_block_ms << ", update template: " << time_update_block_template_ms << ", pack txs: " << time_pack_txs_ms << ", relay: " << time_relay_ms);
  
      return p_verification_result->m_added_to_main_chain;
    }
    //-----------------------------------------------------------------------------------------------
    void core::on_synchronized()
    {
      m_miner.on_synchronized();
    }
    bool core::get_backward_blocks_sizes(uint64_t from_height, std::vector<size_t>& sizes, size_t count)
    {
      return m_blockchain_storage.get_backward_blocks_sizes(from_height, sizes, count);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::add_new_block(const block& b, block_verification_context& bvc)
    {
      return m_blockchain_storage.add_new_block(b, bvc);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::parse_block(const blobdata& block_blob, block& b, block_verification_context& bvc)
    {
      if (block_blob.size() > get_max_block_size())
      {
        LOG_PRINT_L0("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected");
        bvc.m_verification_failed = true;
        return false;
      }
  
      b = AUTO_VAL_INIT_T(block);
      if (!parse_and_validate_block_from_blob(block_blob, b))
      {
        LOG_PRINT_L0("Failed to parse and validate new block");
        bvc.m_verification_failed = true;
        return false;
      }
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::pre_validate_block(block& b, block_verification_context& bvc, const crypto::hash& id)
    {
      return m_blockchain_storage.pre_validate_relayed_block(b, bvc, id);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate)
    {
      bvc = AUTO_VAL_INIT_T(block_verification_context);
      block  b = AUTO_VAL_INIT(b);
      if (!parse_block(block_blob, b, bvc))
      {
        LOG_PRINT_L0("Failed to parse and validate new block");
        bvc.m_verification_failed = true;
        return false;
      }
      return handle_incoming_block(b, bvc, update_miner_blocktemplate);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::handle_incoming_block(const block& b, block_verification_context& bvc, bool update_miner_blocktemplate)
    {
      bool r = add_new_block(b, bvc);
      if (update_miner_blocktemplate && bvc.m_added_to_main_chain)
        update_miner_block_template();
      return r;
    }
    //-----------------------------------------------------------------------------------------------
    crypto::hash core::get_tail_id()
    {
      return m_blockchain_storage.get_top_block_id();
    }
    //-----------------------------------------------------------------------------------------------
    size_t core::get_pool_transactions_count()
    {
      return m_mempool.get_transactions_count();
    }
    //-----------------------------------------------------------------------------------------------
    bool core::have_block(const crypto::hash& id)
    {
      return m_blockchain_storage.have_block(id);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob)
    {
      return parse_and_validate_tx_from_blob(blob, tx, tx_hash);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_pool_transactions(std::list<transaction>& txs)
    {
      return m_mempool.get_transactions(txs);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_short_chain_history(std::list<crypto::hash>& ids)
    {
      return m_blockchain_storage.get_short_chain_history(ids);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, currency_connection_context& context)const 
    {
      return m_blockchain_storage.handle_get_objects(arg, rsp);
    }
    //-----------------------------------------------------------------------------------------------
    crypto::hash core::get_block_id_by_height(uint64_t height)const 
    {
      return m_blockchain_storage.get_block_id_by_height(height);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::get_block_by_hash(const crypto::hash &h, block &blk) {
      return m_blockchain_storage.get_block_by_hash(h, blk);
    }
    //-----------------------------------------------------------------------------------------------
  //   void core::get_all_known_block_ids(std::list<crypto::hash> &main, std::list<crypto::hash> &alt, std::list<crypto::hash> &invalid) {
  //     m_blockchain_storage.get_all_known_block_ids(main, alt, invalid);
  //   }
    //-----------------------------------------------------------------------------------------------
    std::string core::print_pool(bool short_format)
    {
      return m_mempool.print_pool(short_format);
    }
    //-----------------------------------------------------------------------------------------------
    bool core::clear_pool()
    {
      m_mempool.clear();
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::update_miner_block_template()
    {
      notify_blockchain_update_listeners();
      m_miner.on_block_chain_update();
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    bool core::on_idle()
    {
      if(!m_starter_message_showed)
      {
        LOG_PRINT_L0(ENDL
          << "**********************************************************************" << ENDL 
          << "The daemon will start synchronizing with the network. It may take up to several hours." << ENDL 
          << ENDL
          << "You can adjust verbosity by using command: \"set_log <level>\", where 0 is the least verbose and 3 is the most." << ENDL
          << ENDL
          << "Use \"help\" command to list all available commands." << ENDL
          << ENDL
          << "Note: in case you need to interrupt the process, use \"exit\" command. Otherwise, the current progress might not be saved." << ENDL 
          << "**********************************************************************");
        m_starter_message_showed = true;
      }
  
      m_prune_alt_blocks_interval.do_call([this](){return m_blockchain_storage.prune_aged_alt_blocks();});
      m_check_free_space_interval.do_call([this]()
      {
          uint64_t available;
          TRY_ENTRY()
          {
            available = tools::get_free_space(m_config_folder);
          }
          CATCH_ENTRY("core::on_idle tools::get_free_space exception ", true);
          if (available >= MINIMUM_REQUIRED_FREE_SPACE_BYTES)
            return true;
          m_stop_senders.from_free_space("Free space at data directory is critically low ("
            + std::to_string(available / (1024 * 1024))
            + " MB, while "
            + std::to_string(MINIMUM_REQUIRED_FREE_SPACE_BYTES / (1024 * 1024))
            + " MB is required), daemon will stop immediately");
          return true;
      });
      m_miner.on_idle();
      m_mempool.on_idle();
      return true;
    }
    //-----------------------------------------------------------------------------------------------
    void core::add_blockchain_update_listener(i_blockchain_update_listener *l)
    {
      CRITICAL_REGION_LOCAL(m_blockchain_update_listeners_lock);
      m_blockchain_update_listeners.push_back(l);
    }
    //-----------------------------------------------------------------------------------------------
    void core::remove_blockchain_update_listener(i_blockchain_update_listener *l)
    {
      CRITICAL_REGION_LOCAL(m_blockchain_update_listeners_lock);
      m_blockchain_update_listeners.erase(std::remove(m_blockchain_update_listeners.begin(), m_blockchain_update_listeners.end(), l), m_blockchain_update_listeners.end());
    }
    //-----------------------------------------------------------------------------------------------
    void core::notify_blockchain_update_listeners()
    {
      CRITICAL_REGION_LOCAL(m_blockchain_update_listeners_lock);
      for(auto l : m_blockchain_update_listeners)
        l->on_blockchain_update();
    }
    //-----------------------------------------------------------------------------------------------
  
  }
  #undef LOG_DEFAULT_CHANNEL 
  #define LOG_DEFAULT_CHANNEL NULL