diff options
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 2 | ||||
-rw-r--r-- | src/cryptonote_core/tx_pool.cpp | 50 | ||||
-rw-r--r-- | src/daemon/executor.cpp | 7 | ||||
-rw-r--r-- | src/daemon/executor.h | 4 | ||||
-rw-r--r-- | src/daemonizer/posix_daemonizer.inl | 9 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 16 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.cpp | 2 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 67 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 9 |
9 files changed, 122 insertions, 44 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 5f8db45ad..f9a17bcb5 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2860,7 +2860,7 @@ bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const needed_fee += (blob_size % 1024) ? 1 : 0; needed_fee *= fee_per_kb; - if (fee < needed_fee) + if (fee < needed_fee * 0.98) // keep a little buffer on acceptance { MERROR_VER("transaction fee is not enough: " << print_money(fee) << ", minimum fee: " << print_money(needed_fee)); return false; diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 4dd2832ac..ea19b6b48 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -614,7 +614,7 @@ namespace cryptonote CRITICAL_REGION_LOCAL(m_transactions_lock); - uint64_t best_coinbase = 0; + uint64_t best_coinbase = 0, coinbase; total_size = 0; fee = 0; @@ -622,11 +622,9 @@ namespace cryptonote get_block_reward(median_size, total_size, already_generated_coins, best_coinbase, version); -#if 1 - size_t max_total_size = (130 * median_size) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; -#else - size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; -#endif + size_t max_total_size_pre_v5 = (130 * median_size) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; + size_t max_total_size_v5 = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; + size_t max_total_size = version >= 5 ? max_total_size_v5 : max_total_size_pre_v5; std::unordered_set<crypto::key_image> k_images; LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool"); @@ -644,21 +642,35 @@ namespace cryptonote continue; } - // If we're getting lower coinbase tx, - // stop including more tx - uint64_t block_reward; - if(!get_block_reward(median_size, total_size + tx_it->second.blob_size, already_generated_coins, block_reward, version)) + // start using the optimal filling algorithm from v5 + if (version >= 5) { - LOG_PRINT_L2(" would exceed maximum block size"); - sorted_it++; - continue; + // If we're getting lower coinbase tx, + // stop including more tx + uint64_t block_reward; + if(!get_block_reward(median_size, total_size + tx_it->second.blob_size, already_generated_coins, block_reward, version)) + { + LOG_PRINT_L2(" would exceed maximum block size"); + sorted_it++; + continue; + } + coinbase = block_reward + fee + tx_it->second.fee; + if (coinbase < template_accept_threshold(best_coinbase)) + { + LOG_PRINT_L2(" would decrease coinbase to " << print_money(coinbase)); + sorted_it++; + continue; + } } - uint64_t coinbase = block_reward + fee + tx_it->second.fee; - if (coinbase < template_accept_threshold(best_coinbase)) + else { - LOG_PRINT_L2(" would decrease coinbase to " << print_money(coinbase)); - sorted_it++; - continue; + // If we've exceeded the penalty free size, + // stop including more tx + if (total_size > median_size) + { + LOG_PRINT_L2(" would exceed median block size"); + break; + } } // Skip transactions that are not ready to be @@ -680,9 +692,7 @@ namespace cryptonote bl.tx_hashes.push_back(tx_it->first); total_size += tx_it->second.blob_size; fee += tx_it->second.fee; -#if 0 best_coinbase = coinbase; -#endif append_key_images(k_images, tx_it->second.tx); sorted_it++; LOG_PRINT_L2(" added, new block size " << total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase)); diff --git a/src/daemon/executor.cpp b/src/daemon/executor.cpp index 53e1c7647..6130bfa28 100644 --- a/src/daemon/executor.cpp +++ b/src/daemon/executor.cpp @@ -63,6 +63,13 @@ namespace daemonize return t_daemon{vm}; } + bool t_executor::run_non_interactive( + boost::program_options::variables_map const & vm + ) + { + return t_daemon{vm}.run(false); + } + bool t_executor::run_interactive( boost::program_options::variables_map const & vm ) diff --git a/src/daemon/executor.h b/src/daemon/executor.h index b36c819ea..137e7209c 100644 --- a/src/daemon/executor.h +++ b/src/daemon/executor.h @@ -56,6 +56,10 @@ namespace daemonize boost::program_options::variables_map const & vm ); + bool run_non_interactive( + boost::program_options::variables_map const & vm + ); + bool run_interactive( boost::program_options::variables_map const & vm ); diff --git a/src/daemonizer/posix_daemonizer.inl b/src/daemonizer/posix_daemonizer.inl index 6ddaacc9d..f8be15dda 100644 --- a/src/daemonizer/posix_daemonizer.inl +++ b/src/daemonizer/posix_daemonizer.inl @@ -43,6 +43,10 @@ namespace daemonizer "detach" , "Run as daemon" }; + const command_line::arg_descriptor<bool> arg_non_interactive = { + "non-interactive" + , "Run non-interactive" + }; } inline void init_options( @@ -51,6 +55,7 @@ namespace daemonizer ) { command_line::add_arg(normal_options, arg_detach); + command_line::add_arg(normal_options, arg_non_interactive); } inline boost::filesystem::path get_default_data_dir() @@ -79,6 +84,10 @@ namespace daemonizer auto daemon = executor.create_daemon(vm); return daemon.run(); } + else if (command_line::has_arg(vm, arg_non_interactive)) + { + return executor.run_non_interactive(vm); + } else { //LOG_PRINT_L0("Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 8fcefc06b..134841a25 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -851,21 +851,7 @@ bool simple_wallet::set_log(const std::vector<std::string> &args) fail_msg_writer() << tr("usage: set_log <log_level_number_0-4> | <categories>"); return true; } - uint16_t l = 0; - if(epee::string_tools::get_xtype_from_string(l, args[0])) - { - if(4 < l) - { - fail_msg_writer() << tr("wrong number range, use: set_log <log_level_number_0-4>"); - return true; - } - - mlog_set_log_level(l); - } - else - { - mlog_set_categories(args.front().c_str()); - } + mlog_set_log(args[0].c_str()); return true; } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index ea2a66275..8e86c87b3 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -494,7 +494,7 @@ void WalletManagerFactory::setLogLevel(int level) void WalletManagerFactory::setLogCategories(const std::string &categories) { - mlog_set_categories(categories.c_str()); + mlog_set_log(categories.c_str()); } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index dff848a92..dce1ee9de 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1381,6 +1381,8 @@ void wallet2::pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_hei //---------------------------------------------------------------------------------------------------- void wallet2::update_pool_state() { + MDEBUG("update_pool_state start"); + // get the pool state cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::request req; cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::response res; @@ -1390,6 +1392,7 @@ void wallet2::update_pool_state() THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_transaction_pool"); THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_transaction_pool"); THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error); + MDEBUG("update_pool_state got pool"); // remove any pending tx that's not in the pool std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin(); @@ -1444,6 +1447,7 @@ void wallet2::update_pool_state() } } } + MDEBUG("update_pool_state done first loop"); // remove pool txes to us that aren't in the pool anymore std::unordered_map<crypto::hash, wallet2::payment_details>::iterator uit = m_unconfirmed_payments.begin(); @@ -1465,6 +1469,7 @@ void wallet2::update_pool_state() m_unconfirmed_payments.erase(pit); } } + MDEBUG("update_pool_state done second loop"); // add new pool txes to us for (auto it: res.transactions) @@ -1473,6 +1478,11 @@ void wallet2::update_pool_state() if(epee::string_tools::parse_hexstr_to_binbuff(it.id_hash, txid_data) && txid_data.size() == sizeof(crypto::hash)) { const crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data()); + if (m_scanned_pool_txs[0].find(txid) != m_scanned_pool_txs[0].end() || m_scanned_pool_txs[1].find(txid) != m_scanned_pool_txs[1].end()) + { + LOG_PRINT_L2("Already seen " << txid << ", skipped"); + continue; + } if (m_unconfirmed_payments.find(txid) == m_unconfirmed_payments.end()) { LOG_PRINT_L1("Found new pool tx: " << txid); @@ -1491,9 +1501,11 @@ void wallet2::update_pool_state() cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req; cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(it.id_hash); + MDEBUG("asking for " << it.id_hash); req.decode_as_json = false; m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout); + MDEBUG("asked for " << it.id_hash << ", got " << r << " and " << res.status); m_daemon_rpc_mutex.unlock(); if (r && res.status == CORE_RPC_STATUS_OK) { @@ -1512,6 +1524,12 @@ void wallet2::update_pool_state() if (tx_hash == txid) { process_new_transaction(txid, tx, std::vector<uint64_t>(), 0, time(NULL), false, true); + m_scanned_pool_txs[0].insert(txid); + if (m_scanned_pool_txs[0].size() > 5000) + { + std::swap(m_scanned_pool_txs[0], m_scanned_pool_txs[1]); + m_scanned_pool_txs[0].clear(); + } } else { @@ -1550,7 +1568,7 @@ void wallet2::update_pool_state() } else { - LOG_PRINT_L1("Already saw that one"); + LOG_PRINT_L1("Already saw that one, it's for us"); } } else @@ -1558,6 +1576,7 @@ void wallet2::update_pool_state() LOG_PRINT_L0("Failed to parse txid"); } } + MDEBUG("update_pool_state end"); } //---------------------------------------------------------------------------------------------------- void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history) @@ -3379,7 +3398,7 @@ uint64_t wallet2::get_per_kb_fee() int wallet2::get_fee_algorithm() { // changes at v3 and v5 - if (use_fork_rules(5, -720 * 14)) + if (use_fork_rules(5, 0)) return 2; if (use_fork_rules(3, -720 * 14)) return 1; @@ -4120,7 +4139,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money) co return picks; } -static bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) +bool wallet2::should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const { if (!use_rct) return false; @@ -4128,9 +4147,43 @@ static bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const return false; if (unused_dust_indices.empty() && unused_transfers_indices.empty()) return false; + // we want at least one free rct output to avoid a corner case where + // we'd choose a non rct output which doesn't have enough "siblings" + // value-wise on the chain, and thus can't be mixed + bool found = false; + for (auto i: unused_dust_indices) + { + if (m_transfers[i].is_rct()) + { + found = true; + break; + } + } + if (!found) for (auto i: unused_transfers_indices) + { + if (m_transfers[i].is_rct()) + { + found = true; + break; + } + } + if (!found) + return false; return true; } +std::vector<size_t> wallet2::get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const +{ + std::vector<size_t> indices; + for (size_t n: unused_dust_indices) + if (m_transfers[n].is_rct()) + indices.push_back(n); + for (size_t n: unused_transfers_indices) + if (m_transfers[n].is_rct()) + indices.push_back(n); + return indices; +} + // Another implementation of transaction creation that is hopefully better // While there is anything left to pay, it goes through random outputs and tries // to fill the next destination/amount. If it fully fills it, it will use the @@ -4195,8 +4248,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination); // gather all our dust and non dust outputs - const std::vector<size_t> unused_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, true, trusted_daemon); - for (size_t i: unused_indices) + for (size_t i = 0; i < m_transfers.size(); ++i) { const transfer_details& td = m_transfers[i]; if (!td.m_spent && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td)) @@ -4279,7 +4331,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp size_t idx; if ((dsts.empty() || dsts[0].amount == 0) && !adding_fee) { // the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too - idx = pop_best_value(unused_dust_indices.empty() ? unused_transfers_indices : unused_dust_indices, tx.selected_transfers, true); + std::vector<size_t> indices = get_only_rct(unused_dust_indices, unused_transfers_indices); + idx = pop_best_value(indices, tx.selected_transfers, true); // since we're trying to add a second output which is not strictly needed, // we only add it if it's unrelated enough to the first one @@ -4289,6 +4342,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp LOG_PRINT_L2("Second outout was not strictly needed, and relatedness " << relatedness << ", not adding"); break; } + pop_if_present(unused_transfers_indices, idx); + pop_if_present(unused_dust_indices, idx); } else if (!prefered_inputs.empty()) { idx = pop_back(prefered_inputs); pop_if_present(unused_transfers_indices, idx); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 5c8d0ae86..565cd9870 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -485,6 +485,10 @@ namespace tools if(ver < 17) return; a & m_unconfirmed_payments; + if(ver < 18) + return; + a & m_scanned_pool_txs[0]; + a & m_scanned_pool_txs[1]; } /*! @@ -633,6 +637,8 @@ namespace tools void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::list<size_t> &selected_transfers, size_t fake_outputs_count); bool wallet_generate_key_image_helper(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki); crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const; + bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const; + std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const; cryptonote::account_base m_account; boost::optional<epee::net_utils::http::login> m_daemon_login; @@ -677,9 +683,10 @@ namespace tools bool m_confirm_missing_payment_id; bool m_ask_password; NodeRPCProxy m_node_rpc_proxy; + std::unordered_set<crypto::hash> m_scanned_pool_txs[2]; }; } -BOOST_CLASS_VERSION(tools::wallet2, 17) +BOOST_CLASS_VERSION(tools::wallet2, 18) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 7) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6) |