boost::optional<std::string> NodeRPCProxy::get_fee_quantization_mask(uint64_t &fee_quantization_mask) const { uint64_t height; boost::optional<std::string> result = get_height(height); if (result) return result; if (m_offline) return boost::optional<std::string>("offline"); if (m_dynamic_base_fee_estimate_cached_height != height) { cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::response resp_t = AUTO_VAL_INIT(resp_t); m_daemon_rpc_mutex.lock(); req_t.grace_blocks = m_dynamic_base_fee_estimate_grace_blocks; bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_fee_estimate", req_t, resp_t, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get fee estimate"); m_dynamic_base_fee_estimate = resp_t.fee; m_dynamic_base_fee_estimate_cached_height = height; m_fee_quantization_mask = resp_t.quantization_mask; } fee_quantization_mask = m_fee_quantization_mask; if (fee_quantization_mask == 0) { MERROR("Fee quantization mask is 0, forcing to 1"); fee_quantization_mask = 1; } return boost::optional<std::string>(); }
//--------------------------------------------------------------------------------- bool tx_memory_pool::remove_transaction_keyimages(const transaction& tx) { CRITICAL_REGION_LOCAL(m_transactions_lock); BOOST_FOREACH(const txin_v& vi, tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(vi, const txin_to_key, txin, false); auto it = m_spent_key_images.find(txin.k_image); CHECK_AND_ASSERT_MES(it != m_spent_key_images.end(), false, "failed to find transaction input in key images. img=" << txin.k_image << ENDL << "transaction id = " << get_transaction_hash(tx)); std::unordered_set<crypto::hash>& key_image_set = it->second; CHECK_AND_ASSERT_MES(key_image_set.size(), false, "empty key_image set, img=" << txin.k_image << ENDL << "transaction id = " << get_transaction_hash(tx)); auto it_in_set = key_image_set.find(get_transaction_hash(tx)); CHECK_AND_ASSERT_MES(it_in_set != key_image_set.end(), false, "transaction id not found in key_image set, img=" << txin.k_image << ENDL << "transaction id = " << get_transaction_hash(tx)); key_image_set.erase(it_in_set); if (!key_image_set.size()) { //it is now empty hash container for this key_image m_spent_key_images.erase(it); } } return true; }
bool simpleminer::text_job_details_to_native_job_details(const job_details& job, simpleminer::job_details_native& native_details) { bool r = epee::string_tools::parse_hexstr_to_binbuff(job.blob, native_details.blob); CHECK_AND_ASSERT_MES(r, false, "wrong buffer sent from pool server"); r = epee::string_tools::parse_tpod_from_hex_string(job.target, native_details.target); CHECK_AND_ASSERT_MES(r, false, "wrong buffer sent from pool server"); native_details.job_id = job.job_id; return true; }
//--------------------------------------------------------------------------- bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str) { crypto::hash h = null_hash; bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h); CHECK_AND_ASSERT_MES(r, false, "WRONG HASH IN CHECKPOINTS!!!"); CHECK_AND_ASSERT_MES(0 == m_points.count(height), false, "WRONG HASH IN CHECKPOINTS!!!"); m_points[height] = h; return true; }
//----------------------------------------------------------------------------------------------- bool core::init(const CoreConfig& config, const MinerConfig& minerConfig, bool load_existing) { m_config_folder = config.configFolder; bool 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, load_existing); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); r = m_miner->init(minerConfig); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); return load_state_data(); }
void fill_transfer_details(const currency::transaction& tx, const tools::money_transfer2_details& td, view::wallet_transfer_info_details& res_td) { for (auto si: td.spent_indices) { CHECK_AND_ASSERT_MES(si < tx.vin.size(), void(), "Internal error: wrong tx transfer details: spend index=" << si << " is greater than transaction inputs vector " << tx.vin.size()); res_td.spn.push_back(currency::print_money(boost::get<currency::txin_to_key>(tx.vin[si]).amount)); } for (auto ri : td.receive_indices) { CHECK_AND_ASSERT_MES(ri < tx.vout.size(), void(), "Internal error: wrong tx transfer details: reciev index=" << ri << " is greater than transaction outputs vector " << tx.vout.size()); res_td.rcv.push_back(currency::print_money(tx.vout[ri].amount)); } }
//--------------------------------------------------------------------------- bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str) { crypto::hash h = null_hash; bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h); CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!"); // return false if adding at a height we already have AND the hash is different if (m_points.count(height)) { CHECK_AND_ASSERT_MES(h == m_points[height], false, "Checkpoint at given height already exists, and hash for new checkpoint was different!"); } m_points[height] = h; return true; }
bool daemon_backend::get_transfer_address(const std::string& adr_str, currency::account_public_address& addr) { if (!adr_str.size()) return false; std::string addr_str_local = adr_str; if (adr_str[0] == '@') { //referred by alias name if (adr_str.size() < 2) return false; std::string pure_alias_name = adr_str.substr(1); CHECK_AND_ASSERT_MES(currency::validate_alias_name(pure_alias_name), false, "wrong name set in transfer command"); //currency::alias_info_base ai = AUTO_VAL_INIT(ai); currency::COMMAND_RPC_GET_ALIAS_DETAILS::response alias_info = AUTO_VAL_INIT(alias_info); if (!m_rpc_proxy.get_alias_info(pure_alias_name, alias_info)) return false; if (alias_info.status != CORE_RPC_STATUS_OK) return false; addr_str_local = alias_info.alias_details.address; } if (!get_account_address_from_str(addr, addr_str_local)) { return false; } return true; }
//------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::init(const boost::program_options::variables_map& vm) { m_net_server.set_threads_prefix("RPC"); bool r = handle_command_line(vm); CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server"); return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(m_port, m_bind_ip); }
bool communicate(const std::string url, t_request& req, t_response& rsp, const std::string& ip, const std::string& port, bool use_json, bool use_jrpc = false) { epee::net_utils::http::http_simple_client http_client; bool r = http_client.connect(ip, port, 1000); CHECK_AND_ASSERT_MES(r, false, "failed to connect"); if(use_json) { if(use_jrpc) { epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t); req_t.jsonrpc = "2.0"; req_t.id = epee::serialization::storage_entry(10); req_t.method = "command_example_1"; req_t.params = req; epee::json_rpc::response<t_response, std::string> resp_t = AUTO_VAL_INIT(resp_t); if(!epee::net_utils::invoke_http_json_remote_command2("/request_json_rpc", req_t, resp_t, http_client)) { return false; } rsp = resp_t.result; return true; }else return epee::net_utils::invoke_http_json_remote_command2(url, req, rsp, http_client); } else return epee::net_utils::invoke_http_bin_remote_command2(url, req, rsp, http_client); }
bool demo_http_server::on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, connection_context& ctxt) { CHECK_AND_ASSERT_MES(req.sub == demo::get_test_data(), false, "wrong request"); res.m_success = true; res.subs.push_back(req.sub); return true; }
//--------------------------------------------------------------- bool generate_genesis_block( block& bl , std::string const & genesis_tx , uint32_t nonce ) { //genesis block bl = boost::value_initialized<block>(); account_public_address ac = boost::value_initialized<account_public_address>(); std::vector<size_t> sz; construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis blobdata txb = tx_to_blob(bl.miner_tx); std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb); std::string genesis_coinbase_tx_hex = config::GENESIS_TX; blobdata tx_bl; string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl); bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx); CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); bl.major_version = CURRENT_BLOCK_MAJOR_VERSION; bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; bl.timestamp = 0; bl.nonce = nonce; miner::find_nonce_for_given_block(bl, 1, 0); bl.invalidate_hashes(); return true; }
boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const { if (m_offline) return boost::optional<std::string>("offline"); if (m_rpc_version == 0) { cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_VERSION::response resp_t = AUTO_VAL_INIT(resp_t); m_daemon_rpc_mutex.lock(); bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get daemon RPC version"); m_rpc_version = resp_t.version; } rpc_version = m_rpc_version; return boost::optional<std::string>(); }
//--------------------------------------------------------------------------------- bool tx_memory_pool::append_key_images(std::unordered_set<crypto::key_image>& k_images, const transaction& tx) { for(size_t i = 0; i!= tx.vin.size(); i++) { CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false); auto i_res = k_images.insert(itk.k_image); CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << itk.k_image); } return true; }
bool download_wait(const download_async_handle &control) { CHECK_AND_ASSERT_MES(control != 0, false, "NULL async download handle"); { boost::lock_guard<boost::mutex> lock(control->mutex); if (control->stopped) return true; } control->thread.join(); return true; }
bool checkpoints::check_for_conflicts(const checkpoints& other) const { for (auto& pt : other.get_points()) { if (m_points.count(pt.first)) { CHECK_AND_ASSERT_MES(pt.second == m_points.at(pt.first), false, "Checkpoint at given height already exists, and hash for new checkpoint was different!"); } } return true; }
bool simpleminer::init(const boost::program_options::variables_map& vm) { std::string pool_addr = command_line::get_arg(vm, arg_pool_addr); //parse ip and address std::string::size_type p = pool_addr.find(':'); CHECK_AND_ASSERT_MES(p != std::string::npos && (p + 1 != pool_addr.size()), false, "Wrong srv address syntax"); m_pool_ip = pool_addr.substr(0, p); m_pool_port = pool_addr.substr(p + 1, pool_addr.size()); m_login = command_line::get_arg(vm, arg_login); m_pass = command_line::get_arg(vm, arg_pass); return true; }
boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const { if (m_offline) return boost::optional<std::string>("offline"); if (m_earliest_height[version] == 0) { cryptonote::COMMAND_RPC_HARD_FORK_INFO::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_HARD_FORK_INFO::response resp_t = AUTO_VAL_INIT(resp_t); m_daemon_rpc_mutex.lock(); req_t.version = version; bool r = net_utils::invoke_http_json_rpc("/json_rpc", "hard_fork_info", req_t, resp_t, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get hard fork status"); m_earliest_height[version] = resp_t.earliest_height; } earliest_height = m_earliest_height[version]; return boost::optional<std::string>(); }
//----------------------------------------------------------------------------------------------- bool core::handle_incoming_block(const Block& b, block_verification_context& bvc, bool control_miner, bool relay_block) { if (control_miner) { pause_mining(); } m_blockchain_storage.add_new_block(b, bvc); if (control_miner) { update_block_template_and_resume_mining(); } if (relay_block && bvc.m_added_to_main_chain) { std::list<crypto::hash> missed_txs; std::list<Transaction> txs; m_blockchain_storage.get_transactions(b.txHashes, txs, missed_txs); if (!missed_txs.empty() && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b)) { LOG_PRINT_L0("Block added, but it seems that reorganize just happened after that, do not relay this block"); } else { CHECK_AND_ASSERT_MES(txs.size() == b.txHashes.size() && missed_txs.empty(), false, "can't find some transactions in found block:" << get_block_hash(b) << " txs.size()=" << txs.size() << ", b.txHashes.size()=" << b.txHashes.size() << ", missed_txs.size()" << missed_txs.size()); NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg); arg.hop = 0; arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height(); bool r = block_to_blob(b, arg.b.block); CHECK_AND_ASSERT_MES(r, false, "failed to serialize block"); for (auto& tx : txs) { arg.b.txs.push_back(t_serializable_object_to_blob(tx)); } cryptonote_connection_context exclude_context = boost::value_initialized<cryptonote_connection_context>(); m_pprotocol->relay_block(arg, exclude_context); } } return true; }
boost::optional<std::string> NodeRPCProxy::get_info() const { if (m_offline) return boost::optional<std::string>("offline"); const time_t now = time(NULL); if (now >= m_get_info_time + 30) // re-cache every 30 seconds { cryptonote::COMMAND_RPC_GET_INFO::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_INFO::response resp_t = AUTO_VAL_INIT(resp_t); m_daemon_rpc_mutex.lock(); bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_info", req_t, resp_t, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get target blockchain height"); m_height = resp_t.height; m_target_height = resp_t.target_height; m_block_weight_limit = resp_t.block_weight_limit ? resp_t.block_weight_limit : resp_t.block_size_limit; m_get_info_time = now; } return boost::optional<std::string>(); }
bool Currency::generateGenesisBlock() { m_genesisBlock = boost::value_initialized<Block>(); // Hard code coinbase tx in genesis block, because "tru" generating tx use random, but genesis should be always the same std::string genesisCoinbaseTxHex = GENESIS_COINBASE_TX_HEX; blobdata minerTxBlob; epee::string_tools::parse_hexstr_to_binbuff(genesisCoinbaseTxHex, minerTxBlob); bool r = parse_and_validate_tx_from_blob(minerTxBlob, m_genesisBlock.minerTx); CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); m_genesisBlock.majorVersion = BLOCK_MAJOR_VERSION_1; m_genesisBlock.minorVersion = BLOCK_MINOR_VERSION_0; m_genesisBlock.timestamp = 0; m_genesisBlock.nonce = 70; if (m_testnet) { ++m_genesisBlock.nonce; } //miner::find_nonce_for_given_block(bl, 1, 0); return true; }
bool scratchpad_wrapper::init(const std::string& config_folder) { m_config_folder = config_folder; LOG_PRINT_MAGENTA("Loading scratchpad cache...", LOG_LEVEL_0); bool success_from_cache = false; if (epee::file_io_utils::load_file_to_vector(config_folder + "/" + CURRENCY_BLOCKCHAINDATA_SCRATCHPAD_CACHE, m_scratchpad_cache) && m_scratchpad_cache.size()) { LOG_PRINT_MAGENTA("from " << config_folder << "/" << CURRENCY_BLOCKCHAINDATA_SCRATCHPAD_CACHE << " have just been loaded loaded " << m_scratchpad_cache.size() << " elements", LOG_LEVEL_1); size_t sz = m_rdb_scratchpad.size(); if (m_scratchpad_cache.size() && sz == m_scratchpad_cache.size() && m_scratchpad_cache[m_scratchpad_cache.size() - 1] == m_rdb_scratchpad[m_rdb_scratchpad.size() - 1]) { success_from_cache = true; LOG_PRINT_MAGENTA("Scratchpad loaded from cache file OK (" << m_scratchpad_cache.size() << " elements, " << (m_scratchpad_cache.size() * 32) / 1024 << " KB)", LOG_LEVEL_0); } else { LOG_PRINT_MAGENTA("Scratchpad file [" << m_scratchpad_cache.size() << "]:" << (m_scratchpad_cache.size() ? m_scratchpad_cache[m_scratchpad_cache.size() - 1]:currency::null_hash) << ")missmatch with db [" << m_rdb_scratchpad.size() << "]:" << m_rdb_scratchpad[m_rdb_scratchpad.size() - 1], LOG_LEVEL_0); } } boost::system::error_code ec; boost::filesystem::remove(config_folder + "/" + CURRENCY_BLOCKCHAINDATA_SCRATCHPAD_CACHE, ec); LOG_PRINT_MAGENTA(config_folder << "/" << CURRENCY_BLOCKCHAINDATA_SCRATCHPAD_CACHE << " was removed, status: " << ec, LOG_LEVEL_1); if (!success_from_cache) { LOG_PRINT_MAGENTA("Loading scratchpad from db...", LOG_LEVEL_0); //load scratchpad from db to cache PROF_L1_START(cache_load_timer); bool res = m_rdb_scratchpad.load_all_itmes_to_container(m_scratchpad_cache); CHECK_AND_ASSERT_MES(res, false, "scratchpad loading failed"); PROF_L1_FINISH(cache_load_timer); LOG_PRINT_MAGENTA("Scratchpad loaded from db OK (" << m_scratchpad_cache.size() << " elements, " << (m_scratchpad_cache.size() * 32) / 1024 << " KB)" << PROF_L1_STR_MS_STR(" in ", cache_load_timer, " ms"), LOG_LEVEL_0); } return true; }
void daemon_backend::main_worker(const po::variables_map& vm) { view::daemon_status_info dsi = AUTO_VAL_INIT(dsi); dsi.difficulty = "---"; m_pview->update_daemon_status(dsi); //initialize objects LOG_PRINT_L0("Initializing p2p server..."); dsi.text_state = "Initializing p2p server"; m_pview->update_daemon_status(dsi); bool res = m_p2psrv.init(vm); CHECK_AND_ASSERT_MES(res, void(), "Failed to initialize p2p server."); LOG_PRINT_L0("P2p server initialized OK on port: " << m_p2psrv.get_this_peer_port()); //LOG_PRINT_L0("Starting UPnP"); //upnp_helper.run_port_mapping_loop(p2psrv.get_this_peer_port(), p2psrv.get_this_peer_port(), 20*60*1000); LOG_PRINT_L0("Initializing currency protocol..."); dsi.text_state = "Initializing currency protocol"; m_pview->update_daemon_status(dsi); res = m_cprotocol.init(vm); CHECK_AND_ASSERT_MES(res, void(), "Failed to initialize currency protocol."); LOG_PRINT_L0("Currency protocol initialized OK"); LOG_PRINT_L0("Initializing core rpc server..."); dsi.text_state = "Initializing core rpc server"; m_pview->update_daemon_status(dsi); res = m_rpc_server.init(vm); CHECK_AND_ASSERT_MES(res, void(), "Failed to initialize core rpc server."); LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << m_rpc_server.get_binded_port(), LOG_LEVEL_0); //initialize core here LOG_PRINT_L0("Initializing core..."); dsi.text_state = "Initializing core"; m_pview->update_daemon_status(dsi); res = m_ccore.init(vm); CHECK_AND_ASSERT_MES(res, void(), "Failed to initialize core"); LOG_PRINT_L0("Core initialized OK"); LOG_PRINT_L0("Starting core rpc server..."); dsi.text_state = "Starting core rpc server"; m_pview->update_daemon_status(dsi); res = m_rpc_server.run(2, false); CHECK_AND_ASSERT_MES(res, void(), "Failed to initialize core rpc server."); LOG_PRINT_L0("Core rpc server started ok"); LOG_PRINT_L0("Starting p2p net loop..."); dsi.text_state = "Starting network loop"; m_pview->update_daemon_status(dsi); m_p2psrv.run(false); LOG_PRINT_L0("p2p net loop stopped"); //go to monitoring view loop loop(); dsi.daemon_network_state = 3; CRITICAL_REGION_BEGIN(m_wallet_lock); if(m_wallet->get_wallet_path().size()) { LOG_PRINT_L0("Storing wallet data..."); dsi.text_state = "Storing wallet data..."; m_pview->update_daemon_status(dsi); m_wallet->store(); } CRITICAL_REGION_END(); LOG_PRINT_L0("Stopping core p2p server..."); dsi.text_state = "Stopping p2p network server"; m_pview->update_daemon_status(dsi); m_p2psrv.send_stop_signal(); m_p2psrv.timed_wait_server_stop(10); //stop components LOG_PRINT_L0("Stopping core rpc server..."); dsi.text_state = "Stopping rpc network server"; m_pview->update_daemon_status(dsi); m_rpc_server.send_stop_signal(); m_rpc_server.timed_wait_server_stop(5000); //deinitialize components LOG_PRINT_L0("Deinitializing core..."); dsi.text_state = "Deinitializing core"; m_pview->update_daemon_status(dsi); m_ccore.deinit(); LOG_PRINT_L0("Deinitializing rpc server ..."); dsi.text_state = "Deinitializing rpc server"; m_pview->update_daemon_status(dsi); m_rpc_server.deinit(); LOG_PRINT_L0("Deinitializing currency_protocol..."); dsi.text_state = "Deinitializing currency_protocol"; m_pview->update_daemon_status(dsi); m_cprotocol.deinit(); LOG_PRINT_L0("Deinitializing p2p..."); dsi.text_state = "Deinitializing p2p"; m_pview->update_daemon_status(dsi); m_p2psrv.deinit(); m_ccore.set_currency_protocol(NULL); m_cprotocol.set_p2p_endpoint(NULL); LOG_PRINT("Node stopped.", LOG_LEVEL_0); dsi.text_state = "Node stopped"; m_pview->update_daemon_status(dsi); m_pview->on_backend_stopped(); }
//--------------------------------------------------------------- bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); keypair txkey = keypair::generate(); add_tx_pub_key_to_extra(tx, txkey.pub); if(!extra_nonce.empty()) if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) return false; txin_gen in; in.height = height; uint64_t block_reward; if(!get_block_reward(median_size, current_block_size, already_generated_coins, block_reward, hard_fork_version)) { LOG_PRINT_L0("Block is too big"); return false; } #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) LOG_PRINT_L1("Creating block template: reward " << block_reward << ", fee " << fee); #endif block_reward += fee; // from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and // keeps the paid amount almost the same. The unpaid remainder gets pushed back to the // emission schedule // from hard fork 4, we use a single "dusty" output. This makes the tx even smaller, // and avoids the quantization. These outputs will be added as rct outputs with identity // masks, to they can be used as rct inputs. if (hard_fork_version >= 2 && hard_fork_version < 4) { block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD; } std::vector<uint64_t> out_amounts; decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::DEFAULT_DUST_THRESHOLD, [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); if (height == 0 || hard_fork_version >= 4) { // the genesis block was not decomposed, for unknown reasons while (max_outs < out_amounts.size()) { //out_amounts[out_amounts.size() - 2] += out_amounts.back(); //out_amounts.resize(out_amounts.size() - 1); out_amounts[1] += out_amounts[0]; for (size_t n = 1; n < out_amounts.size(); ++n) out_amounts[n - 1] = out_amounts[n]; out_amounts.resize(out_amounts.size() - 1); } } else { CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded"); } uint64_t summary_amounts = 0; for (size_t no = 0; no < out_amounts.size(); no++) { crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);; crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")"); r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")"); txout_to_key tk; tk.key = out_eph_public_key; tx_out out; summary_amounts += out.amount = out_amounts[no]; out.target = tk; tx.vout.push_back(out); } CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward); if (hard_fork_version >= 4) tx.version = 2; else tx.version = 1; //lock tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; tx.vin.push_back(in); tx.invalidate_hashes(); //LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "(" << print_money(block_reward - fee) << "+" << print_money(fee) // << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2); return true; }
//--------------------------------------------------------------- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct) { std::vector<rct::key> amount_keys; tx.set_null(); amount_keys.clear(); tx.version = rct ? 2 : 1; tx.unlock_time = unlock_time; tx.extra = extra; keypair txkey = keypair::generate(); remove_field_from_tx_extra(tx.extra, typeid(tx_extra_pub_key)); add_tx_pub_key_to_extra(tx, txkey.pub); tx_key = txkey.sec; // if we have a stealth payment id, find it and encrypt it with the tx key now std::vector<tx_extra_field> tx_extra_fields; if (parse_tx_extra(tx.extra, tx_extra_fields)) { tx_extra_nonce extra_nonce; if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) { crypto::hash8 payment_id = null_hash8; if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) { LOG_PRINT_L2("Encrypting payment id " << payment_id); crypto::public_key view_key_pub = get_destination_view_key_pub(destinations, sender_account_keys); if (view_key_pub == null_pkey) { LOG_ERROR("Destinations have to have exactly one output to support encrypted payment ids"); return false; } if (!encrypt_payment_id(payment_id, view_key_pub, txkey.sec)) { LOG_ERROR("Failed to encrypt payment id"); return false; } std::string extra_nonce; set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id); remove_field_from_tx_extra(tx.extra, typeid(tx_extra_nonce)); if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) { LOG_ERROR("Failed to add encrypted payment id to tx extra"); return false; } LOG_PRINT_L1("Encrypted payment ID: " << payment_id); } } } else { LOG_ERROR("Failed to parse tx extra"); return false; } struct input_generation_context_data { keypair in_ephemeral; }; std::vector<input_generation_context_data> in_contexts; uint64_t summary_inputs_money = 0; //fill inputs int idx = -1; for(const tx_source_entry& src_entr: sources) { ++idx; if(src_entr.real_output >= src_entr.outputs.size()) { LOG_ERROR("real_output index (" << src_entr.real_output << ")bigger than output_keys.size()=" << src_entr.outputs.size()); return false; } summary_inputs_money += src_entr.amount; //key_derivation recv_derivation; in_contexts.push_back(input_generation_context_data()); keypair& in_ephemeral = in_contexts.back().in_ephemeral; crypto::key_image img; if(!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img)) return false; //check that derivated key is equal with real output key if( !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) ) { LOG_ERROR("derived public key mismatch with output public key at index " << idx << ", real out " << src_entr.real_output << "! "<< ENDL << "derived_key:" << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second) ); LOG_ERROR("amount " << src_entr.amount << ", rct " << src_entr.rct); LOG_ERROR("tx pubkey " << src_entr.real_out_tx_key << ", real_output_in_tx_index " << src_entr.real_output_in_tx_index); return false; } //put key image into tx input txin_to_key input_to_key; input_to_key.amount = src_entr.amount; input_to_key.k_image = img; //fill outputs array and use relative offsets for(const tx_source_entry::output_entry& out_entry: src_entr.outputs) input_to_key.key_offsets.push_back(out_entry.first); input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets); tx.vin.push_back(input_to_key); } // "Shuffle" outs std::vector<tx_destination_entry> shuffled_dsts(destinations); std::sort(shuffled_dsts.begin(), shuffled_dsts.end(), [](const tx_destination_entry& de1, const tx_destination_entry& de2) { return de1.amount < de2.amount; } ); uint64_t summary_outs_money = 0; //fill outputs size_t output_index = 0; for(const tx_destination_entry& dst_entr: shuffled_dsts) { CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount); crypto::key_derivation derivation; crypto::public_key out_eph_public_key; bool r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, txkey.sec, derivation); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << txkey.sec << ")"); if (tx.version > 1) { crypto::secret_key scalar1; crypto::derivation_to_scalar(derivation, output_index, scalar1); amount_keys.push_back(rct::sk2rct(scalar1)); } r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")"); tx_out out; out.amount = dst_entr.amount; txout_to_key tk; tk.key = out_eph_public_key; out.target = tk; tx.vout.push_back(out); output_index++; summary_outs_money += dst_entr.amount; } //check money if(summary_outs_money > summary_inputs_money ) { LOG_ERROR("Transaction inputs money ("<< summary_inputs_money << ") less than outputs money (" << summary_outs_money << ")"); return false; } // check for watch only wallet bool zero_secret_key = true; for (size_t i = 0; i < sizeof(sender_account_keys.m_spend_secret_key); ++i) zero_secret_key &= (sender_account_keys.m_spend_secret_key.data[i] == 0); if (zero_secret_key) { MDEBUG("Null secret key, skipping signatures"); } if (tx.version == 1) { //generate ring signatures crypto::hash tx_prefix_hash; get_transaction_prefix_hash(tx, tx_prefix_hash); std::stringstream ss_ring_s; size_t i = 0; for(const tx_source_entry& src_entr: sources) { ss_ring_s << "pub_keys:" << ENDL; std::vector<const crypto::public_key*> keys_ptrs; std::vector<crypto::public_key> keys(src_entr.outputs.size()); size_t ii = 0; for(const tx_source_entry::output_entry& o: src_entr.outputs) { keys[ii] = rct2pk(o.second.dest); keys_ptrs.push_back(&keys[ii]); ss_ring_s << o.second.dest << ENDL; ++ii; } tx.signatures.push_back(std::vector<crypto::signature>()); std::vector<crypto::signature>& sigs = tx.signatures.back(); sigs.resize(src_entr.outputs.size()); if (!zero_secret_key) crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data()); ss_ring_s << "signatures:" << ENDL; std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;}); ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL; i++; } MCINFO("construct_tx", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str()); } else { size_t n_total_outs = sources[0].outputs.size(); // only for non-simple rct // the non-simple version is slightly smaller, but assumes all real inputs // are on the same index, so can only be used if there just one ring. bool use_simple_rct = sources.size() > 1; if (!use_simple_rct) { // non simple ringct requires all real inputs to be at the same index for all inputs for(const tx_source_entry& src_entr: sources) { if(src_entr.real_output != sources.begin()->real_output) { LOG_ERROR("All inputs must have the same index for non-simple ringct"); return false; } } // enforce same mixin for all outputs for (size_t i = 1; i < sources.size(); ++i) { if (n_total_outs != sources[i].outputs.size()) { LOG_ERROR("Non-simple ringct transaction has varying mixin"); return false; } } } uint64_t amount_in = 0, amount_out = 0; rct::ctkeyV inSk; // mixRing indexing is done the other way round for simple rct::ctkeyM mixRing(use_simple_rct ? sources.size() : n_total_outs); rct::keyV destinations; std::vector<uint64_t> inamounts, outamounts; std::vector<unsigned int> index; for (size_t i = 0; i < sources.size(); ++i) { rct::ctkey ctkey; amount_in += sources[i].amount; inamounts.push_back(sources[i].amount); index.push_back(sources[i].real_output); // inSk: (secret key, mask) ctkey.dest = rct::sk2rct(in_contexts[i].in_ephemeral.sec); ctkey.mask = sources[i].mask; inSk.push_back(ctkey); // inPk: (public key, commitment) // will be done when filling in mixRing } for (size_t i = 0; i < tx.vout.size(); ++i) { destinations.push_back(rct::pk2rct(boost::get<txout_to_key>(tx.vout[i].target).key)); outamounts.push_back(tx.vout[i].amount); amount_out += tx.vout[i].amount; } if (use_simple_rct) { // mixRing indexing is done the other way round for simple for (size_t i = 0; i < sources.size(); ++i) { mixRing[i].resize(sources[i].outputs.size()); for (size_t n = 0; n < sources[i].outputs.size(); ++n) { mixRing[i][n] = sources[i].outputs[n].second; } } } else { for (size_t i = 0; i < n_total_outs; ++i) // same index assumption { mixRing[i].resize(sources.size()); for (size_t n = 0; n < sources.size(); ++n) { mixRing[i][n] = sources[n].outputs[i].second; } } } // fee if (!use_simple_rct && amount_in > amount_out) outamounts.push_back(amount_in - amount_out); // zero out all amounts to mask rct outputs, real amounts are now encrypted for (size_t i = 0; i < tx.vin.size(); ++i) { if (sources[i].rct) boost::get<txin_to_key>(tx.vin[i]).amount = 0; } for (size_t i = 0; i < tx.vout.size(); ++i) tx.vout[i].amount = 0; crypto::hash tx_prefix_hash; get_transaction_prefix_hash(tx, tx_prefix_hash); rct::ctkeyV outSk; if (use_simple_rct) tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, index, outSk); else tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk); // same index assumption CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout"); MCINFO("construct_tx", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL); } tx.invalidate_hashes(); return true; }
int main(int argc, char* argv[]) { TRY_ENTRY(); string_tools::set_module_name_and_folder(argv[0]); //set up logging options log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); log_space::log_singletone::add_logger(LOGGER_FILE, log_space::log_singletone::get_default_log_file().c_str(), log_space::log_singletone::get_default_log_folder().c_str()); LOG_PRINT("Demo server starting ...", LOG_LEVEL_0); demo::demo_http_server srv; start_default_console(&srv, "#"); std::string bind_param = "0.0.0.0"; std::string port = "83"; if(!srv.init(port, bind_param)) { LOG_ERROR("Failed to initialize srv!"); return 1; } //log loop srv.run(); size_t count = 0; while (!srv.is_stop()) { demo::COMMAND_EXAMPLE_1::request req; req.sub = demo::get_test_data(); demo::COMMAND_EXAMPLE_1::response rsp; bool r = false; if(count%2) {//invoke json r = communicate("/request_api_json_1", req, rsp, "127.0.0.1", port, true, true); }else{ r = communicate("/request_api_bin_1", req, rsp, "127.0.0.1", port, false); } CHECK_AND_ASSERT_MES(r, false, "failed to invoke http request"); CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response"); CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response"); CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response"); //misc_utils::sleep_no_w(1000); ++count; } bool r = srv.wait_stop(); CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop"); srv.deinit(); LOG_PRINT("Demo server stoped.", LOG_LEVEL_0); return 1; CATCH_ENTRY_L0("main", 1); }
bool download_finished(const download_async_handle &control) { CHECK_AND_ASSERT_MES(control != 0, false, "NULL async download handle"); boost::lock_guard<boost::mutex> lock(control->mutex); return control->stopped; }
bool Currency::constructMinerTx(size_t height, size_t medianSize, uint64_t alreadyGeneratedCoins, size_t currentBlockSize, uint64_t fee, const AccountPublicAddress& minerAddress, Transaction& tx, const blobdata& extraNonce/* = blobdata()*/, size_t maxOuts/* = 1*/) const { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); KeyPair txkey = KeyPair::generate(); add_tx_pub_key_to_extra(tx, txkey.pub); if (!extraNonce.empty()) { if (!add_extra_nonce_to_tx_extra(tx.extra, extraNonce)) { return false; } } TransactionInputGenerate in; in.height = height; uint64_t blockReward; int64_t emissionChange; if (!getBlockReward(medianSize, currentBlockSize, alreadyGeneratedCoins, fee, blockReward, emissionChange)) { LOG_PRINT_L0("Block is too big"); return false; } #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) LOG_PRINT_L1("Creating block template: reward " << blockReward << ", fee " << fee); #endif std::vector<uint64_t> outAmounts; decompose_amount_into_digits(blockReward, m_defaultDustThreshold, [&outAmounts](uint64_t a_chunk) { outAmounts.push_back(a_chunk); }, [&outAmounts](uint64_t a_dust) { outAmounts.push_back(a_dust); }); CHECK_AND_ASSERT_MES(1 <= maxOuts, false, "max_out must be non-zero"); while (maxOuts < outAmounts.size()) { outAmounts[outAmounts.size() - 2] += outAmounts.back(); outAmounts.resize(outAmounts.size() - 1); } uint64_t summaryAmounts = 0; for (size_t no = 0; no < outAmounts.size(); no++) { crypto::key_derivation derivation = boost::value_initialized<crypto::key_derivation>(); crypto::public_key outEphemeralPubKey = boost::value_initialized<crypto::public_key>(); bool r = crypto::generate_key_derivation(minerAddress.m_viewPublicKey, txkey.sec, derivation); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << minerAddress.m_viewPublicKey << ", " << txkey.sec << ")"); r = crypto::derive_public_key(derivation, no, minerAddress.m_spendPublicKey, outEphemeralPubKey); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< minerAddress.m_spendPublicKey << ")"); TransactionOutputToKey tk; tk.key = outEphemeralPubKey; TransactionOutput out; summaryAmounts += out.amount = outAmounts[no]; out.target = tk; tx.vout.push_back(out); } CHECK_AND_ASSERT_MES(summaryAmounts == blockReward, false, "Failed to construct miner tx, summaryAmounts = " << summaryAmounts << " not equal blockReward = " << blockReward); tx.version = CURRENT_TRANSACTION_VERSION; //lock tx.unlockTime = height + m_minedMoneyUnlockWindow; tx.vin.push_back(in); return true; }
bool download_error(const download_async_handle &control) { CHECK_AND_ASSERT_MES(control != 0, false, "NULL async download handle"); boost::lock_guard<boost::mutex> lock(control->mutex); return !control->success; }
bool daemon_backend::start(int argc, char* argv[], view::i_view* pview_handler) { m_stop_singal_sent = false; if(pview_handler) m_pview = pview_handler; view::daemon_status_info dsi = AUTO_VAL_INIT(dsi); dsi.difficulty = "---"; dsi.text_state = "Initializing..."; pview_handler->update_daemon_status(dsi); //#ifdef WIN32 //_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); //#endif log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); LOG_PRINT_L0("Initing..."); TRY_ENTRY(); po::options_description desc_cmd_only("Command line options"); po::options_description desc_cmd_sett("Command line options and settings options"); command_line::add_arg(desc_cmd_only, command_line::arg_help); command_line::add_arg(desc_cmd_only, command_line::arg_version); command_line::add_arg(desc_cmd_only, command_line::arg_os_version); // tools::get_default_data_dir() can't be called during static initialization command_line::add_arg(desc_cmd_only, command_line::arg_data_dir, tools::get_default_data_dir()); command_line::add_arg(desc_cmd_only, command_line::arg_config_file); command_line::add_arg(desc_cmd_sett, command_line::arg_log_file); command_line::add_arg(desc_cmd_sett, command_line::arg_log_level); command_line::add_arg(desc_cmd_sett, command_line::arg_console); command_line::add_arg(desc_cmd_sett, command_line::arg_show_details); command_line::add_arg(desc_cmd_sett, arg_alloc_win_console); currency::core::init_options(desc_cmd_sett); currency::core_rpc_server::init_options(desc_cmd_sett); nodetool::node_server<currency::t_currency_protocol_handler<currency::core> >::init_options(desc_cmd_sett); currency::miner::init_options(desc_cmd_sett); po::options_description desc_options("Allowed options"); desc_options.add(desc_cmd_only).add(desc_cmd_sett); po::variables_map vm; bool r = command_line::handle_error_helper(desc_options, [&]() { po::store(po::parse_command_line(argc, argv, desc_options), vm); if (command_line::get_arg(vm, command_line::arg_help)) { std::cout << CURRENCY_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL; std::cout << desc_options << std::endl; return false; } m_data_dir = command_line::get_arg(vm, command_line::arg_data_dir); std::string config = command_line::get_arg(vm, command_line::arg_config_file); boost::filesystem::path data_dir_path(m_data_dir); boost::filesystem::path config_path(config); if (!config_path.has_parent_path()) { config_path = data_dir_path / config_path; } boost::system::error_code ec; if (boost::filesystem::exists(config_path, ec)) { po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), desc_cmd_sett), vm); } po::notify(vm); return true; }); if (!r) return false; //set up logging options if(command_line::has_arg(vm, arg_alloc_win_console)) { log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); } boost::filesystem::path log_file_path(command_line::get_arg(vm, command_line::arg_log_file)); if (log_file_path.empty()) log_file_path = log_space::log_singletone::get_default_log_file(); std::string log_dir; log_dir = log_file_path.has_parent_path() ? log_file_path.parent_path().string() : log_space::log_singletone::get_default_log_folder(); log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str()); LOG_PRINT_L0(CURRENCY_NAME << " v" << PROJECT_VERSION_LONG); LOG_PRINT("Module folder: " << argv[0], LOG_LEVEL_0); bool res = true; currency::checkpoints checkpoints; res = currency::create_checkpoints(checkpoints); CHECK_AND_ASSERT_MES(res, false, "Failed to initialize checkpoints"); m_ccore.set_checkpoints(std::move(checkpoints)); m_main_worker_thread = std::thread([this, vm](){main_worker(vm);}); return true; CATCH_ENTRY_L0("main", 1); }