//----------------------------------------------------------------------------------------------- bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block) { tvc = boost::value_initialized<tx_verification_context>(); //want to process all transactions sequentially CRITICAL_REGION_LOCAL(m_incoming_tx_lock); if(tx_blob.size() > m_currency.maxTxSize()) { LOG_PRINT_L0("WRONG TRANSACTION BLOB, too big size " << tx_blob.size() << ", rejected"); tvc.m_verifivation_failed = true; return false; } crypto::hash tx_hash = null_hash; crypto::hash tx_prefixt_hash = null_hash; Transaction tx; if(!parse_tx_from_blob(tx, tx_hash, tx_prefixt_hash, tx_blob)) { LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to parse, rejected"); tvc.m_verifivation_failed = true; return false; } //std::cout << "!"<< tx.vin.size() << std::endl; if(!check_tx_syntax(tx)) { LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected"); tvc.m_verifivation_failed = true; return false; } if(!check_tx_semantic(tx, keeped_by_block)) { LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected"); tvc.m_verifivation_failed = true; return false; } bool r = add_new_tx(tx, tx_hash, tx_prefixt_hash, tx_blob.size(), tvc, keeped_by_block); if(tvc.m_verifivation_failed) { if (!tvc.m_tx_fee_too_small) { LOG_PRINT_RED_L0("Transaction verification failed: " << tx_hash); } else { LOG_PRINT_L0("Transaction verification failed: " << tx_hash); } } else if(tvc.m_verifivation_impossible) { LOG_PRINT_RED_L0("Transaction verification impossible: " << tx_hash); } if (tvc.m_added_to_pool) { LOG_PRINT_L1("tx added: " << tx_hash); poolUpdated(); } return r; }
extern "C" uint64_t pNXT_submit_tx(currency::core *m_core,currency::simple_wallet *wallet,unsigned char *txbytes,int16_t size) { int i,j; crypto::hash h; uint64_t txid = 0; blobdata txb,b; transaction tx = AUTO_VAL_INIT(tx); txin_to_key input_to_key = AUTO_VAL_INIT(input_to_key); NOTIFY_NEW_TRANSACTIONS::request req; currency_connection_context fake_context = AUTO_VAL_INIT(fake_context); tx_verification_context tvc = AUTO_VAL_INIT(tvc); if ( m_core == 0 || wallet == 0 ) { printf("pNXT_submit_tx missing m_core.%p or wallet.%p\n",m_core,wallet); return(0); } tx.vin.clear(); tx.vout.clear(); tx.signatures.clear(); keypair txkey = keypair::generate(); add_tx_pub_key_to_extra(tx, txkey.pub); if ( sizeof(input_to_key.k_image) != 32 ) { printf("FATAL: expected sizeof(input_to_key.k_image) to be 32!\n"); return(0); } j = add_byte(&tx,&input_to_key,0,size&0xff); j = add_byte(&tx,&input_to_key,j,(size>>8)&0xff); for (i=0; i<size; i++) j = add_byte(&tx,&input_to_key,j,txbytes[i]); if ( j != 0 ) tx.vin.push_back(input_to_key); tx.version = 0; txb = tx_to_blob(tx); printf("FROM submit jl777\n"); if ( !m_core->handle_incoming_tx(txb,tvc,false) ) { LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx"); return(0); } if ( tvc.m_verifivation_failed ) { LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed"); return(0); } if( !tvc.m_should_be_relayed ) { LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed"); return(0); } req.txs.push_back(txb); m_core->get_protocol()->relay_transactions(req,fake_context); get_transaction_hash(tx,h); txid = calc_txid((unsigned char *)&h,sizeof(h)); return(txid); }
std::vector<std::string> parse_dns_public(const char *s) { unsigned ip0, ip1, ip2, ip3; char c; std::vector<std::string> dns_public_addr; if (!strcmp(s, "tcp")) { for (size_t i = 0; i < sizeof(DEFAULT_DNS_PUBLIC_ADDR) / sizeof(DEFAULT_DNS_PUBLIC_ADDR[0]); ++i) dns_public_addr.push_back(DEFAULT_DNS_PUBLIC_ADDR[i]); LOG_PRINT_L0("Using default public DNS server(s): " << boost::join(dns_public_addr, ", ") << " (TCP)"); } else if (sscanf(s, "tcp://%u.%u.%u.%u%c", &ip0, &ip1, &ip2, &ip3, &c) == 4) { if (ip0 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255) { MERROR("Invalid IP: " << s << ", using default"); } else { dns_public_addr.push_back(std::string(s + strlen("tcp://"))); } } else { MERROR("Invalid DNS_PUBLIC contents, ignored"); } return dns_public_addr; }
t_daemon t_executor::create_daemon( boost::program_options::variables_map const & vm ) { LOG_PRINT_L0("Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ") Daemonised"); return t_daemon{vm, public_rpc_port}; }
//----------------------------------------------------------------------------------------------- bool core::handle_incoming_block_blob(const blobdata& block_blob, block_verification_context& bvc, bool control_miner, bool relay_block) { if (block_blob.size() > m_currency.maxBlockBlobSize()) { LOG_PRINT_L0("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected"); bvc.m_verifivation_failed = true; return false; } Block b = AUTO_VAL_INIT(b); if (!parse_and_validate_block_from_blob(block_blob, b)) { LOG_PRINT_L0("Failed to parse and validate new block"); bvc.m_verifivation_failed = true; return false; } return handle_incoming_block(b, bvc, control_miner, relay_block); }
bool scratchpad_wrapper::push_block_scratchpad_data(const block& b) { PROFILE_FUNC("scratchpad_wrapper::push_block_scratchpad_data(b)"); bool res = false; { PROFILE_FUNC_SECOND("scratchpad_wrapper::push_block_scratchpad_data-cache"); res = currency::push_block_scratchpad_data(b, m_scratchpad_cache); } { PROFILE_FUNC_SECOND("scratchpad_wrapper::push_block_scratchpad_data-db"); res &= currency::push_block_scratchpad_data(b, m_rdb_scratchpad); } #ifdef SELF_VALIDATE_SCRATCHPAD std::vector<crypto::hash> scratchpad_cache; load_scratchpad_from_db(m_rdb_scratchpad, scratchpad_cache); if (scratchpad_cache != m_scratchpad_cache) { LOG_PRINT_L0("scratchpads mismatch, memory version: " << ENDL << dump_scratchpad(m_scratchpad_cache) << ENDL << "db version:" << ENDL << dump_scratchpad(scratchpad_cache) ); } #endif return res; }
//--------------------------------------------------------------------------------- bool tx_memory_pool::deinit() { if (!tools::create_directories_if_necessary(m_config_folder)) { LOG_PRINT_L0("Failed to create data directory: " << m_config_folder); return false; } std::string state_file_path = m_config_folder + "/" + CURRENCY_POOLDATA_FILENAME; bool res = tools::serialize_obj_to_file(*this, state_file_path); if(!res) { LOG_PRINT_L0("Failed to serialize memory pool to file " << state_file_path); } return true; }
void set_performance_timer_log_level(int level) { if (level < LOG_LEVEL_MIN || level > LOG_LEVEL_MAX) { LOG_PRINT_L0("Wrong log level: " << level << ", using 2"); level = 2; } performance_timer_log_level = level; }
bool test_casual() { LOG_PRINT_L0("Starting miniupnp tests..."); tools::miniupnp_helper hlpr; hlpr.start_regular_mapping(10101, 10101, 10000); boost::this_thread::sleep_for(boost::chrono::milliseconds(50000)); return true; }
bool daemon_backend::update_wallets() { CRITICAL_REGION_LOCAL(m_wallet_lock); if(m_wallet->get_wallet_path().size()) {//wallet is opened if(m_last_daemon_height != m_last_wallet_synch_height) { view::wallet_status_info wsi = AUTO_VAL_INIT(wsi); wsi.wallet_state = view::wallet_status_info::wallet_state_synchronizing; m_pview->update_wallet_status(wsi); try { m_wallet->refresh(); } catch (const tools::error::daemon_busy& /*e*/) { LOG_PRINT_L0("Daemon busy while wallet refresh"); return true; } catch (const std::exception& e) { LOG_PRINT_L0("Failed to refresh wallet: " << e.what()); return false; } catch (...) { LOG_PRINT_L0("Failed to refresh wallet, unknownk exception"); return false; } m_last_wallet_synch_height = m_ccore.get_current_blockchain_height(); wsi.wallet_state = view::wallet_status_info::wallet_state_ready; m_pview->update_wallet_status(wsi); update_wallet_info(); } } return true; }
bool demo_http_server::init(const std::string& bind_port, const std::string& bind_ip) { //set self as callback handler m_net_server.get_config_object().m_phandler = this; //here set folder for hosting reqests m_net_server.get_config_object().m_folder = ""; LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port); return m_net_server.init_server(bind_port, bind_ip); }
//--------------------------------------------------------------------------------- bool tx_memory_pool::init(const std::string& config_folder) { m_config_folder = config_folder; std::string state_file_path = config_folder + "/" + CURRENCY_POOLDATA_FILENAME; boost::system::error_code ec; if(!boost::filesystem::exists(state_file_path, ec)) return true; bool res = tools::unserialize_obj_from_file(*this, state_file_path); if(!res) { LOG_PRINT_L0("Failed to load memory pool from file " << state_file_path); } return res; }
DNSResolver::DNSResolver() : m_data(new DNSResolverData()) { int use_dns_public = 0; const char* dns_public_addr = "8.8.4.4"; if (auto res = getenv("DNS_PUBLIC")) { std::string dns_public(res); // TODO: could allow parsing of IP and protocol: e.g. DNS_PUBLIC=tcp:8.8.8.8 if (dns_public == "tcp") { LOG_PRINT_L0("Using public DNS server: " << dns_public_addr << " (TCP)"); use_dns_public = 1; } } // init libunbound context m_data->m_ub_context = ub_ctx_create(); if (use_dns_public) { ub_ctx_set_fwd(m_data->m_ub_context, dns_public_addr); ub_ctx_set_option(m_data->m_ub_context, "do-udp:", "no"); ub_ctx_set_option(m_data->m_ub_context, "do-tcp:", "yes"); } else { // look for "/etc/resolv.conf" and "/etc/hosts" or platform equivalent ub_ctx_resolvconf(m_data->m_ub_context, NULL); ub_ctx_hosts(m_data->m_ub_context, NULL); } #ifdef DEVELOPER_LIBUNBOUND_OLD #pragma message "Using the work around for old libunbound" { // work around for bug https://www.nlnetlabs.nl/bugs-script/show_bug.cgi?id=515 needed for it to compile on e.g. Debian 7 char * ds_copy = NULL; // this will be the writable copy of string that bugged version of libunbound requires try { char * ds_copy = strdup( ::get_builtin_ds() ); ub_ctx_add_ta(m_data->m_ub_context, ds_copy); } catch(...) { // probably not needed but to work correctly in every case... if (ds_copy) { free(ds_copy); ds_copy=NULL; } // for the strdup throw ; } if (ds_copy) { free(ds_copy); ds_copy=NULL; } // for the strdup } #else // normal version for fixed libunbound ub_ctx_add_ta(m_data->m_ub_context, ::get_builtin_ds() ); #endif }
bool scratchpad_wrapper::deinit() { #ifdef SELF_VALIDATE_SCRATCHPAD std::vector<crypto::hash> scratchpad_cache; load_scratchpad_from_db(m_rdb_scratchpad, scratchpad_cache); if (scratchpad_cache != m_scratchpad_cache) { LOG_PRINT_L0("scratchpads mismatch, memory version: " << ENDL << dump_scratchpad(m_scratchpad_cache) << ENDL << "db version:" << ENDL << dump_scratchpad(scratchpad_cache) ); } #endif epee::file_io_utils::save_buff_to_file(m_config_folder + "/" + CURRENCY_BLOCKCHAINDATA_SCRATCHPAD_CACHE, &m_scratchpad_cache[0], m_scratchpad_cache.size()*sizeof(m_scratchpad_cache[0])); LOG_PRINT_MAGENTA("Stored scratchpad file [" << m_scratchpad_cache.size() << "]:" << m_scratchpad_cache[m_scratchpad_cache.size() - 1] << " to " << m_config_folder << " / " << CURRENCY_BLOCKCHAINDATA_SCRATCHPAD_CACHE, LOG_LEVEL_0); return true; }
//--------------------------------------------------------------------------------- bool tx_memory_pool::remove_stuck_transactions() { CRITICAL_REGION_LOCAL(m_transactions_lock); for(auto it = m_transactions.begin(); it!= m_transactions.end();) { uint64_t tx_age = time(nullptr) - it->second.receive_time; if((tx_age > CURRENCY_MEMPOOL_TX_LIVETIME && !it->second.kept_by_block) /*|| (tx_age > CURRENCY_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && it->second.kept_by_block) */) { LOG_PRINT_L0("Tx " << it->first << " removed from tx pool due to outdated, age: " << tx_age ); m_transactions.erase(it++); } else ++it; } 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 set the level of process detailization* through \"set_log <level>\" command*, where <level> is between 0 (no details) and 4 (very verbose)." << ENDL << ENDL << "Use \"help\" command to see the list of available commands." << ENDL << ENDL << "Note: in case you need to interrupt the process, use \"exit\" command. Otherwise, the current progress won't be saved." << ENDL << "**********************************************************************"); m_starter_message_showed = true; } m_miner->on_idle(); m_mempool.on_idle(); return true; }
//----------------------------------------------------------------------------------------------- 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; }
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); }
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 tx_memory_pool::add_tx(const transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block) { //#9Protection from big transaction flood if(!kept_by_block && blob_size > m_blockchain.get_current_comulative_blocksize_limit() / 2) { LOG_PRINT_L0("transaction is too big for current transaction flow, tx_id: " << id); tvc.m_verifivation_failed = true; return false; } //TODO: add rule for relay, based on tx size/fee ratio if(!check_inputs_types_supported(tx)) { tvc.m_verifivation_failed = true; return false; } uint64_t inputs_amount = 0; if(!get_inputs_money_amount(tx, inputs_amount)) { tvc.m_verifivation_failed = true; return false; } uint64_t outputs_amount = get_outs_money_amount(tx); if(outputs_amount >= inputs_amount) { LOG_PRINT_L0("transaction use more money then it has: use " << outputs_amount << ", have " << inputs_amount); tvc.m_verifivation_failed = true; return false; } //check key images for transaction if it is not kept by block if(!kept_by_block) { if(have_tx_keyimges_as_spent(tx)) { LOG_ERROR("Transaction with id= "<< id << " used already spent key images"); tvc.m_verifivation_failed = true; return false; } } crypto::hash max_used_block_id = null_hash; uint64_t max_used_block_height = 0; bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id); CRITICAL_REGION_LOCAL(m_transactions_lock); if(!ch_inp_res) { if(kept_by_block) { //anyway add this transaction to pool, because it related to block auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details())); CHECK_AND_ASSERT_MES(txd_p.second, false, "transaction already exists at inserting in memory pool"); txd_p.first->second.blob_size = blob_size; txd_p.first->second.tx = tx; txd_p.first->second.fee = inputs_amount - outputs_amount; txd_p.first->second.max_used_block_id = null_hash; txd_p.first->second.max_used_block_height = 0; txd_p.first->second.kept_by_block = kept_by_block; txd_p.first->second.receive_time = time(nullptr); tvc.m_verifivation_impossible = true; tvc.m_added_to_pool = true; } else { LOG_PRINT_L0("tx used wrong inputs, rejected"); tvc.m_verifivation_failed = true; return false; } } else { //update transactions container auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details())); CHECK_AND_ASSERT_MES(txd_p.second, false, "intrnal error: transaction already exists at inserting in memorypool"); txd_p.first->second.blob_size = blob_size; txd_p.first->second.tx = tx; txd_p.first->second.kept_by_block = kept_by_block; txd_p.first->second.fee = inputs_amount - outputs_amount; txd_p.first->second.max_used_block_id = max_used_block_id; txd_p.first->second.max_used_block_height = max_used_block_height; txd_p.first->second.last_failed_height = 0; txd_p.first->second.last_failed_id = null_hash; txd_p.first->second.receive_time = time(nullptr); tvc.m_added_to_pool = true; if(txd_p.first->second.fee > 0) tvc.m_should_be_relayed = true; } tvc.m_verifivation_failed = true; //update image_keys container, here should everything goes ok. BOOST_FOREACH(const auto& in, tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false); std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image]; CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: keeped_by_block=" << kept_by_block << ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL << "tx_id=" << id ); auto ins_res = kei_image_set.insert(id); CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set"); } tvc.m_verifivation_failed = false; //succeed return true; }
//--------------------------------------------------------------------------------- bool tx_memory_pool::add_tx(const transaction &tx, const crypto::hash &id, tx_verification_context& tvc, bool kept_by_block, std::string alias) { size_t blob_size = get_object_blobsize(tx); //#9Protection from big transaction flood if (!kept_by_block && blob_size > currency::get_max_transaction_blob_size(m_blockchain.get_current_blockchain_height())) { LOG_PRINT_L0("transaction is too big (" << blob_size << ")bytes for current transaction flow, tx_id: " << id); tvc.m_verifivation_failed = true; return false; } if (!check_inputs_types_supported(tx)) { tvc.m_verifivation_failed = true; return false; } uint64_t inputs_amount = 0; if (!get_inputs_money_amount(tx, inputs_amount)) { tvc.m_verifivation_failed = true; return false; } uint64_t outputs_amount = get_outs_money_amount(tx); if (outputs_amount >= inputs_amount) { LOG_PRINT_L0("transaction use more money then it has: use " << outputs_amount << ", have " << inputs_amount); tvc.m_verifivation_failed = true; return false; } //check key images for transaction if it is not kept by blockhave_tx_keyimges_as_spent if (!kept_by_block) { if (have_tx_keyimges_as_spent(tx)) { LOG_ERROR("Transaction with id= " << id << " used already spent key images"); tvc.m_verifivation_failed = true; return false; } //transaction spam protection, soft rule if (inputs_amount - outputs_amount < TX_POOL_MINIMUM_FEE) { LOG_ERROR("Transaction with id= " << id << " has too small fee: " << inputs_amount - outputs_amount << ", expected fee: " << DEFAULT_FEE); tvc.m_verifivation_failed = true; return false; } } crypto::hash max_used_block_id = null_hash; uint64_t max_used_block_height = 0; bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id); CRITICAL_REGION_LOCAL(m_transactions_lock); if (!ch_inp_res) { if (kept_by_block) { //if there is a same alias on the block, then delete the tx with the same alias in the pool crypto::hash hash; if (alias.size() && (hash = find_alias(alias)) != null_hash) { transaction tx = AUTO_VAL_INIT(tx); size_t size = 0; uint64_t fee = 0; take_tx(hash, tx, size, fee); LOG_PRINT_L2("Found alias " << alias << " in block, delete pool tx with the same alias: " << id); } //anyway add this transaction to pool, because it related to block auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details())); if (!txd_p.second) { return false; } //CHECK_AND_ASSERT_MES(txd_p.second, false, "transaction already exists at inserting in memory pool"); txd_p.first->second.blob_size = blob_size; txd_p.first->second.tx = tx; txd_p.first->second.fee = inputs_amount - outputs_amount; txd_p.first->second.max_used_block_id = null_hash; txd_p.first->second.max_used_block_height = 0; txd_p.first->second.kept_by_block = kept_by_block; txd_p.first->second.receive_time = time(nullptr); tvc.m_verifivation_impossible = true; tvc.m_added_to_pool = true; } else { LOG_PRINT_L0("tx used wrong inputs, rejected"); tvc.m_verifivation_failed = true; return false; } } else { //check alias repeat or not if (!add_alias_tx_pair(alias, id)) { tvc.m_verifivation_failed = true; tvc.m_added_to_pool = false; return false; } //update transactions container auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details())); if (!txd_p.second) { return false; } //CHECK_AND_ASSERT_MES(txd_p.second, false, "intrnal error: transaction already exists at inserting in memorypool"); txd_p.first->second.blob_size = blob_size; txd_p.first->second.tx = tx; txd_p.first->second.kept_by_block = kept_by_block; txd_p.first->second.fee = inputs_amount - outputs_amount; txd_p.first->second.max_used_block_id = max_used_block_id; txd_p.first->second.max_used_block_height = max_used_block_height; txd_p.first->second.last_failed_height = 0; txd_p.first->second.last_failed_id = null_hash; txd_p.first->second.receive_time = time(nullptr); tvc.m_added_to_pool = true; if (txd_p.first->second.fee > 0) tvc.m_should_be_relayed = true; } tvc.m_verifivation_failed = true; //update image_keys container, here should everything goes ok. BOOST_FOREACH(const auto& in, tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false); std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image]; CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: keeped_by_block=" << kept_by_block << ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL << "tx_id=" << id); auto ins_res = kei_image_set.insert(id); CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set"); } tvc.m_verifivation_failed = false; //succeed return true; }
int main(int argc, char const * argv[]) { try { _note_c("dbg/main", "Begin of main()"); // TODO parse the debug options like set log level right here at start tools::sanitize_locale(); epee::string_tools::set_module_name_and_folder(argv[0]); // Build argument description po::options_description all_options("All"); po::options_description hidden_options("Hidden"); po::options_description visible_options("Options"); po::options_description core_settings("Settings"); po::positional_options_description positional_options; { bf::path default_data_dir = daemonizer::get_default_data_dir(); bf::path default_testnet_data_dir = {default_data_dir / "testnet"}; // Misc Options command_line::add_arg(visible_options, command_line::arg_help); command_line::add_arg(visible_options, command_line::arg_version); command_line::add_arg(visible_options, daemon_args::arg_os_version); bf::path default_conf = default_data_dir / std::string(CRYPTONOTE_NAME ".conf"); command_line::add_arg(visible_options, daemon_args::arg_config_file, default_conf.string()); command_line::add_arg(visible_options, command_line::arg_test_dbg_lock_sleep); cryptonote::core::init_options(core_settings); // Settings bf::path default_log = default_data_dir / std::string(CRYPTONOTE_NAME ".log"); command_line::add_arg(core_settings, daemon_args::arg_log_file, default_log.string()); command_line::add_arg(core_settings, daemon_args::arg_log_level); daemonizer::init_options(hidden_options, visible_options); daemonize::t_executor::init_options(core_settings); // Hidden options command_line::add_arg(hidden_options, daemon_args::arg_command); visible_options.add(core_settings); all_options.add(visible_options); all_options.add(hidden_options); // Positional positional_options.add(daemon_args::arg_command.name, -1); // -1 for unlimited arguments } // Do command line parsing po::variables_map vm; bool ok = command_line::handle_error_helper(visible_options, [&]() { boost::program_options::store( boost::program_options::command_line_parser(argc, argv) .options(all_options).positional(positional_options).run() , vm ); return true; }); if (!ok) return 1; if (command_line::get_arg(vm, command_line::arg_help)) { std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL; std::cout << "Usage: " + std::string{argv[0]} + " [options|settings] [daemon_command...]" << std::endl << std::endl; std::cout << visible_options << std::endl; return 0; } // Monero Version if (command_line::get_arg(vm, command_line::arg_version)) { std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL; return 0; } // OS if (command_line::get_arg(vm, daemon_args::arg_os_version)) { std::cout << "OS: " << tools::get_os_version_string() << ENDL; return 0; } epee::g_test_dbg_lock_sleep = command_line::get_arg(vm, command_line::arg_test_dbg_lock_sleep); std::string db_type = command_line::get_arg(vm, command_line::arg_db_type); // verify that blockchaindb type is valid if(cryptonote::blockchain_db_types.count(db_type) == 0) { std::cout << "Invalid database type (" << db_type << "), available types are:" << std::endl; for (const auto& type : cryptonote::blockchain_db_types) { std::cout << "\t" << type << std::endl; } return 0; } bool testnet_mode = command_line::get_arg(vm, command_line::arg_testnet_on); auto data_dir_arg = testnet_mode ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; // data_dir // default: e.g. ~/.bitmonero/ or ~/.bitmonero/testnet // if data-dir argument given: // absolute path // relative path: relative to cwd // Create data dir if it doesn't exist boost::filesystem::path data_dir = boost::filesystem::absolute( command_line::get_arg(vm, data_dir_arg)); tools::create_directories_if_necessary(data_dir.string()); // FIXME: not sure on windows implementation default, needs further review //bf::path relative_path_base = daemonizer::get_relative_path_base(vm); bf::path relative_path_base = data_dir; std::string config = command_line::get_arg(vm, daemon_args::arg_config_file); boost::filesystem::path data_dir_path(data_dir); boost::filesystem::path config_path(config); if (!config_path.has_parent_path()) { config_path = data_dir / config_path; } boost::system::error_code ec; if (bf::exists(config_path, ec)) { po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), core_settings), vm); } po::notify(vm); // If there are positional options, we're running a daemon command { auto command = command_line::get_arg(vm, daemon_args::arg_command); if (command.size()) { auto rpc_ip_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_ip); auto rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port); if (testnet_mode) { rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_testnet_rpc_bind_port); } uint32_t rpc_ip; uint16_t rpc_port; if (!epee::string_tools::get_ip_int32_from_string(rpc_ip, rpc_ip_str)) { std::cerr << "Invalid IP: " << rpc_ip_str << std::endl; return 1; } if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str)) { std::cerr << "Invalid port: " << rpc_port_str << std::endl; return 1; } daemonize::t_command_server rpc_commands{rpc_ip, rpc_port}; if (rpc_commands.process_command_vec(command)) { return 0; } else { std::cerr << "Unknown command" << std::endl; return 1; } } } // Start with log level 0 epee::log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); // Set log level { int new_log_level = command_line::get_arg(vm, daemon_args::arg_log_level); if(new_log_level < LOG_LEVEL_MIN || new_log_level > LOG_LEVEL_MAX) { LOG_PRINT_L0("Wrong log level value: " << new_log_level); } else if (epee::log_space::get_set_log_detalisation_level(false) != new_log_level) { epee::log_space::get_set_log_detalisation_level(true, new_log_level); int otshell_utils_log_level = 100 - (new_log_level * 20); gCurrentLogger.setDebugLevel(otshell_utils_log_level); LOG_PRINT_L0("LOG_LEVEL set to " << new_log_level); } } // log_file_path // default: <data_dir>/<CRYPTONOTE_NAME>.log // if log-file argument given: // absolute path // relative path: relative to data_dir // Set log file { bf::path log_file_path {data_dir / std::string(CRYPTONOTE_NAME ".log")}; if (! vm["log-file"].defaulted()) log_file_path = command_line::get_arg(vm, daemon_args::arg_log_file); log_file_path = bf::absolute(log_file_path, relative_path_base); epee::log_space::log_singletone::add_logger( LOGGER_FILE , log_file_path.filename().string().c_str() , log_file_path.parent_path().string().c_str() ); } _note_c("dbg/main", "Moving from main() into the daemonize now."); return daemonizer::daemonize(argc, argv, daemonize::t_executor{}, vm); } catch (std::exception const & ex) { LOG_ERROR("Exception in main! " << ex.what()); } catch (...) { LOG_ERROR("Exception in main!"); } return 1; }
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 simpleminer::run() { std::string pool_session_id; simpleminer::job_details_native job = AUTO_VAL_INIT(job); uint64_t last_job_ticks = 0; while(true) { //----------------- last_job_ticks = epee::misc_utils::get_tick_count(); if(!m_http_client.is_connected()) { LOG_PRINT_L0("Connecting " << m_pool_ip << ":" << m_pool_port << "...."); if(!m_http_client.connect(m_pool_ip, m_pool_port, 20000)) { LOG_PRINT_L0("Failed to connect " << m_pool_ip << ":" << m_pool_port << ", sleep...."); epee::misc_utils::sleep_no_w(1000); continue; } //DO AUTH LOG_PRINT_L0("Connected " << m_pool_ip << ":" << m_pool_port << " OK"); COMMAND_RPC_LOGIN::request req = AUTO_VAL_INIT(req); req.login = m_login; req.pass = m_pass; req.agent = "simpleminer/0.1"; COMMAND_RPC_LOGIN::response resp = AUTO_VAL_INIT(resp); if(!epee::net_utils::invoke_http_json_rpc<mining::COMMAND_RPC_LOGIN>("/", req, resp, m_http_client)) { LOG_PRINT_L0("Failed to invoke login " << m_pool_ip << ":" << m_pool_port << ", disconnect and sleep...."); m_http_client.disconnect(); epee::misc_utils::sleep_no_w(1000); continue; } if(resp.status != "OK" || resp.id.empty()) { LOG_PRINT_L0("Failed to login " << m_pool_ip << ":" << m_pool_port << ", disconnect and sleep...."); m_http_client.disconnect(); epee::misc_utils::sleep_no_w(1000); continue; } pool_session_id = resp.id; //78 if (resp.job.blob.empty() && resp.job.target.empty() && resp.job.job_id.empty()) { LOG_PRINT_L0("Job didn't change"); continue; } else if(!text_job_details_to_native_job_details(resp.job, job)) { LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep...."); m_http_client.disconnect(); epee::misc_utils::sleep_no_w(1000); continue; } last_job_ticks = epee::misc_utils::get_tick_count(); } while(epee::misc_utils::get_tick_count() - last_job_ticks < 20000) { //uint32_t c = (*((uint32_t*)&job.blob.data()[39])); ++(*((uint32_t*)&job.blob.data()[39])); crypto::hash h = cryptonote::null_hash; crypto::cn_slow_hash(job.blob.data(), job.blob.size(), h); if( ((uint32_t*)&h)[7] < job.target ) { //found! COMMAND_RPC_SUBMITSHARE::request submit_request = AUTO_VAL_INIT(submit_request); COMMAND_RPC_SUBMITSHARE::response submit_response = AUTO_VAL_INIT(submit_response); submit_request.id = pool_session_id; submit_request.job_id = job.job_id; submit_request.nonce = epee::string_tools::pod_to_hex((*((uint32_t*)&job.blob.data()[39]))); submit_request.result = epee::string_tools::pod_to_hex(h); LOG_PRINT_L0("Share found: nonce=" << submit_request.nonce << " for job=" << job.job_id << ", submitting..."); if(!epee::net_utils::invoke_http_json_rpc<mining::COMMAND_RPC_SUBMITSHARE>("/", submit_request, submit_response, m_http_client)) { LOG_PRINT_L0("Failed to submit share! disconnect and sleep...."); m_http_client.disconnect(); epee::misc_utils::sleep_no_w(1000); break; } if(submit_response.status != "OK") { LOG_PRINT_L0("Failed to submit share! (submitted share rejected) disconnect and sleep...."); m_http_client.disconnect(); epee::misc_utils::sleep_no_w(1000); break; } LOG_PRINT_GREEN("Share submitted successfully!", LOG_LEVEL_0); break; } } //get next job COMMAND_RPC_GETJOB::request getjob_request = AUTO_VAL_INIT(getjob_request); COMMAND_RPC_GETJOB::response getjob_response = AUTO_VAL_INIT(getjob_response); getjob_request.id = pool_session_id; LOG_PRINT_L0("Getting next job..."); if(!epee::net_utils::invoke_http_json_rpc<mining::COMMAND_RPC_GETJOB>("/", getjob_request, getjob_response, m_http_client)) { LOG_PRINT_L0("Can't get new job! Disconnect and sleep...."); m_http_client.disconnect(); epee::misc_utils::sleep_no_w(1000); continue; } if (getjob_response.blob.empty() && getjob_response.target.empty() && getjob_response.job_id.empty()) { LOG_PRINT_L0("Job didn't change"); continue; } else if(!text_job_details_to_native_job_details(getjob_response, job)) { LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep...."); m_http_client.disconnect(); epee::misc_utils::sleep_no_w(1000); continue; } last_job_ticks = epee::misc_utils::get_tick_count(); } return true; }
//--------------------------------------------------------------- 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 load_txt_records_from_dns(std::vector<std::string> &good_records, const std::vector<std::string> &dns_urls) { // Prevent infinite recursion when distributing if (dns_urls.empty()) return false; std::vector<std::vector<std::string> > records; records.resize(dns_urls.size()); std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<int> dis(0, dns_urls.size() - 1); size_t first_index = dis(gen); // send all requests in parallel std::vector<boost::thread> threads(dns_urls.size()); std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false); for (size_t n = 0; n < dns_urls.size(); ++n) { threads[n] = boost::thread([n, dns_urls, &records, &avail, &valid](){ records[n] = tools::DNSResolver::instance().get_txt_record(dns_urls[n], avail[n], valid[n]); }); } for (size_t n = 0; n < dns_urls.size(); ++n) threads[n].join(); size_t cur_index = first_index; do { const std::string &url = dns_urls[cur_index]; if (!avail[cur_index]) { records[cur_index].clear(); LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping."); } if (!valid[cur_index]) { records[cur_index].clear(); LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping."); } cur_index++; if (cur_index == dns_urls.size()) { cur_index = 0; } } while (cur_index != first_index); size_t num_valid_records = 0; for( const auto& record_set : records) { if (record_set.size() != 0) { num_valid_records++; } } if (num_valid_records < 2) { LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received"); return false; } int good_records_index = -1; for (size_t i = 0; i < records.size() - 1; ++i) { if (records[i].size() == 0) continue; for (size_t j = i + 1; j < records.size(); ++j) { if (dns_records_match(records[i], records[j])) { good_records_index = i; break; } } if (good_records_index >= 0) break; } if (good_records_index < 0) { LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched"); return false; } good_records = records[good_records_index]; return true; }