From 31b1c6c10d3d3e5849256dfbb0898b3e3902326b Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 27 Aug 2017 21:04:56 +0100 Subject: [PATCH] simplewallet: new "fee" command to display fee information including expected transaction backlog at different priorities --- src/simplewallet/simplewallet.cpp | 69 +++++++++++++++++++++++++++++-- src/simplewallet/simplewallet.h | 1 + src/wallet/wallet2.cpp | 63 +++++++++++++++++----------- src/wallet/wallet2.h | 7 ++-- 4 files changed, 110 insertions(+), 30 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 479adcaf..ecdae289 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -391,6 +391,61 @@ bool simple_wallet::payment_id(const std::vector &args/* = std::vec return true; } +bool simple_wallet::print_fee_info(const std::vector &args/* = std::vector()*/) +{ + if (!try_connect_to_daemon()) + { + fail_msg_writer() << tr("Cannot connect to daemon"); + return true; + } + const uint64_t per_kb_fee = m_wallet->get_per_kb_fee(); + const uint64_t typical_size_kb = 13; + message_writer() << (boost::format(tr("Current fee is %s monero per kB")) % print_money(per_kb_fee)).str(); + + std::vector fees; + for (uint32_t priority = 1; priority <= 4; ++priority) + { + uint64_t mult = m_wallet->get_fee_multiplier(priority); + fees.push_back(per_kb_fee * typical_size_kb * mult); + } + std::vector> blocks; + try + { + uint64_t base_size = typical_size_kb * 1024; + blocks = m_wallet->estimate_backlog(base_size, base_size + 1023, fees); + } + catch (const std::exception &e) + { + fail_msg_writer() << tr("Error: failed to estimate backlog array size: ") << e.what(); + return true; + } + if (blocks.size() != 4) + { + fail_msg_writer() << tr("Error: bad estimated backlog array size"); + return true; + } + + for (uint32_t priority = 1; priority <= 4; ++priority) + { + uint64_t nblocks_low = blocks[priority - 1].first; + uint64_t nblocks_high = blocks[priority - 1].second; + if (nblocks_low > 0) + { + std::string msg; + if (priority == m_wallet->get_default_priority() || (m_wallet->get_default_priority() == 0 && priority == 2)) + msg = tr(" (current)"); + uint64_t minutes_low = nblocks_low * DIFFICULTY_TARGET_V2 / 60, minutes_high = nblocks_high * DIFFICULTY_TARGET_V2 / 60; + if (nblocks_high == nblocks_low) + message_writer() << (boost::format(tr("%u block (%u minutes) backlog at priority %u%s")) % nblocks_low % minutes_low % priority % msg).str(); + else + message_writer() << (boost::format(tr("%u to %u block (%u to %u minutes) backlog at priority %u")) % nblocks_low % nblocks_high % minutes_low % minutes_high % priority).str(); + } + else + message_writer() << tr("No backlog at priority ") << priority; + } + return true; +} + bool simple_wallet::set_always_confirm_transfers(const std::vector &args/* = std::vector()*/) { const auto pwd_container = get_and_verify_password(); @@ -722,6 +777,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("show_transfer", boost::bind(&simple_wallet::show_transfer, this, _1), tr("Show information about a transfer to/from this address")); m_cmd_binder.set_handler("password", boost::bind(&simple_wallet::change_password, this, _1), tr("Change wallet password")); m_cmd_binder.set_handler("payment_id", boost::bind(&simple_wallet::payment_id, this, _1), tr("Generate a new random full size payment id - these will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids")); + m_cmd_binder.set_handler("fee", boost::bind(&simple_wallet::print_fee_info, this, _1), tr("Print information about fee and current transaction backlog")); m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help")); } //---------------------------------------------------------------------------------------------------- @@ -2461,9 +2517,16 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vectorestimate_backlog(size, fee); - if (nblocks > 0) - prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No)")) % nblocks).str(); + std::vector> nblocks = m_wallet->estimate_backlog(size, size, {fee}); + if (nblocks.size() != 1) + { + prompt << "Internal error checking for backlog. " << tr("Is this okay anyway? (Y/Yes/N/No): "); + } + else + { + if (nblocks[0].first > 0) + prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No)")) % nblocks[0].first).str(); + } } catch (const std::exception &e) { diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index eac4cbc9..079fae9f 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -175,6 +175,7 @@ namespace cryptonote bool show_transfer(const std::vector &args); bool change_password(const std::vector& args); bool payment_id(const std::vector &args); + bool print_fee_info(const std::vector &args); uint64_t get_daemon_blockchain_height(std::string& err); bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 09ca8efe..6c34c3fd 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3457,12 +3457,15 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector default (here, x1 till fee algorithm 2, x4 from it) if (priority == 0) priority = m_default_priority; @@ -5747,10 +5750,14 @@ bool wallet2::is_synced() const return get_blockchain_current_height() >= height; } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::estimate_backlog(uint64_t blob_size, uint64_t fee) +std::vector> wallet2::estimate_backlog(uint64_t min_blob_size, uint64_t max_blob_size, const std::vector &fees) { - THROW_WALLET_EXCEPTION_IF(blob_size == 0, error::wallet_internal_error, "Invalid 0 fee"); - THROW_WALLET_EXCEPTION_IF(fee == 0, error::wallet_internal_error, "Invalid 0 fee"); + THROW_WALLET_EXCEPTION_IF(min_blob_size == 0, error::wallet_internal_error, "Invalid 0 fee"); + THROW_WALLET_EXCEPTION_IF(max_blob_size == 0, error::wallet_internal_error, "Invalid 0 fee"); + for (uint64_t fee: fees) + { + THROW_WALLET_EXCEPTION_IF(fee == 0, error::wallet_internal_error, "Invalid 0 fee"); + } // get txpool backlog epee::json_rpc::request req = AUTO_VAL_INIT(req); @@ -5776,27 +5783,35 @@ uint64_t wallet2::estimate_backlog(uint64_t blob_size, uint64_t fee) THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_info"); THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_info"); THROW_WALLET_EXCEPTION_IF(resp_t.result.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error); - - double our_fee_byte = fee / (double)blob_size; - uint64_t priority_size = 0; - for (const auto &i: res.result.backlog) - { - if (i.blob_size == 0) - { - MWARNING("Got 0 sized blob from txpool, ignored"); - continue; - } - double this_fee_byte = i.fee / (double)i.blob_size; - if (this_fee_byte < our_fee_byte) - continue; - priority_size += i.blob_size; - } - uint64_t full_reward_zone = resp_t.result.block_size_limit / 2; - uint64_t nblocks = (priority_size + full_reward_zone - 1) / full_reward_zone; - MDEBUG("estimate_backlog: priority_size " << priority_size << " for " << our_fee_byte << " (" << our_fee_byte << " piconero fee/byte), " - << nblocks << " blocks at block size " << full_reward_zone); - return nblocks; + + std::vector> blocks; + for (uint64_t fee: fees) + { + double our_fee_byte_min = fee / (double)min_blob_size, our_fee_byte_max = fee / (double)max_blob_size; + uint64_t priority_size_min = 0, priority_size_max = 0; + for (const auto &i: res.result.backlog) + { + if (i.blob_size == 0) + { + MWARNING("Got 0 sized blob from txpool, ignored"); + continue; + } + double this_fee_byte = i.fee / (double)i.blob_size; + if (this_fee_byte >= our_fee_byte_min) + priority_size_min += i.blob_size; + if (this_fee_byte >= our_fee_byte_max) + priority_size_max += i.blob_size; + } + + uint64_t nblocks_min = (priority_size_min + full_reward_zone - 1) / full_reward_zone; + uint64_t nblocks_max = (priority_size_max + full_reward_zone - 1) / full_reward_zone; + MDEBUG("estimate_backlog: priority_size " << priority_size_min << " - " << priority_size_max << " for " << fee + << " (" << our_fee_byte_min << " - " << our_fee_byte_max << " piconero byte fee), " + << nblocks_min << " - " << nblocks_max << " blocks at block size " << full_reward_zone); + blocks.push_back(std::make_pair(nblocks_min, nblocks_max)); + } + return blocks; } //---------------------------------------------------------------------------------------------------- void wallet2::generate_genesis(cryptonote::block& b) { diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f30c9763..86f64e71 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -604,7 +604,10 @@ namespace tools bool is_synced() const; - uint64_t estimate_backlog(uint64_t blob_size, uint64_t fee); + std::vector> estimate_backlog(uint64_t min_blob_size, uint64_t max_blob_size, const std::vector &fees); + + uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm = -1); + uint64_t get_per_kb_fee(); private: /*! @@ -646,9 +649,7 @@ namespace tools void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const; uint64_t get_upper_transaction_size_limit(); std::vector get_unspent_amounts_vector(); - uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm) const; uint64_t get_dynamic_per_kb_fee_estimate(); - uint64_t get_per_kb_fee(); float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const; std::vector pick_preferred_rct_inputs(uint64_t needed_money) const; void set_spent(size_t idx, uint64_t height);