From 1593553e03aef8d44621aaf79a33ba25f69a2bd7 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 1 Aug 2016 22:16:00 +0100 Subject: [PATCH] new unlocked parameter to output_histogram This constrains the number of instances of any amount to the unlocked ones (as defined by the default unlock time setting: outputs with non default unlock time are not considered, so may be counted as unlocked even if they are not actually unlocked). --- src/blockchain_db/blockchain_db.h | 7 ++++--- src/blockchain_db/lmdb/db_lmdb.cpp | 23 ++++++++++++++++++++--- src/blockchain_db/lmdb/db_lmdb.h | 7 ++++--- src/cryptonote_core/blockchain.cpp | 4 ++-- src/cryptonote_core/blockchain.h | 3 ++- src/rpc/core_rpc_server.cpp | 2 +- src/rpc/core_rpc_server_commands_defs.h | 2 ++ src/wallet/wallet2.cpp | 9 +++++---- src/wallet/wallet2.h | 2 +- 9 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index ab5d2d44..4c2157a3 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -1140,7 +1140,7 @@ public: * * @return the tx hash and output index */ - virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) = 0; + virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const = 0; /** * @brief gets some outputs' tx hashes and indices @@ -1153,7 +1153,7 @@ public: * @param offsets a list of amount-specific output indices * @param indices return-by-reference a list of tx hashes and output indices (as pairs) */ - virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) = 0; + virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) const = 0; /** * @brief gets outputs' data @@ -1305,10 +1305,11 @@ public: * @brief return a histogram of outputs on the blockchain * * @param amounts optional set of amounts to lookup + * @param unlocked whether to restrict count to unlocked outputs * * @return a set of amount/instances */ - virtual std::map get_output_histogram(const std::vector &amounts) const = 0; + virtual std::map get_output_histogram(const std::vector &amounts, bool unlocked) const = 0; /** * @brief is BlockchainDB in read-only mode? diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 2cd3943e..4f1e84a0 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -1945,7 +1945,7 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t& return ret; } -tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) +tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); std::vector < uint64_t > offsets; @@ -2551,7 +2551,7 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &indices) +void BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -2586,7 +2586,7 @@ void BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const std:: LOG_PRINT_L3("db3: " << db3); } -std::map BlockchainLMDB::get_output_histogram(const std::vector &amounts) const +std::map BlockchainLMDB::get_output_histogram(const std::vector &amounts, bool unlocked) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -2638,6 +2638,23 @@ std::map BlockchainLMDB::get_output_histogram(const std::vec } } + if (unlocked) { + const uint64_t blockchain_height = height(); + for (auto i: histogram) { + uint64_t amount = i.first; + uint64_t num_elems = i.second; + while (num_elems > 0) { + const tx_out_index toi = get_output_tx_and_index(amount, num_elems - 1); + const uint64_t height = get_tx_block_height(toi.first); + if (height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= blockchain_height) + break; + --num_elems; + } + // modifying second does not invalidate the iterator + i.second = num_elems; + } + } + TXN_POSTFIX_RDONLY(); return histogram; diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index d7a78617..d60701bb 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -224,8 +224,8 @@ public: virtual void get_output_tx_and_index_from_global(const std::vector &global_indices, std::vector &tx_out_indices) const; - virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index); - virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices); + virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const; + virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) const; virtual std::vector get_tx_amount_output_indices(const uint64_t tx_id) const; @@ -263,10 +263,11 @@ public: * @brief return a histogram of outputs on the blockchain * * @param amounts optional set of amounts to lookup + * @param unlocked whether to restrict count to unlocked outputs * * @return a set of amount/instances */ - std::map get_output_histogram(const std::vector &amounts) const; + std::map get_output_histogram(const std::vector &amounts, bool unlocked) const; private: void do_resize(uint64_t size_increase=0); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index d332f899..36a233ee 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3316,9 +3316,9 @@ bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, ui return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting); } -std::map Blockchain:: get_output_histogram(const std::vector &amounts) const +std::map Blockchain:: get_output_histogram(const std::vector &amounts, bool unlocked) const { - return m_db->get_output_histogram(amounts); + return m_db->get_output_histogram(amounts, unlocked); } void Blockchain::load_compiled_in_block_hashes() diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 21086d57..903e0096 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -688,10 +688,11 @@ namespace cryptonote * @brief return a histogram of outputs on the blockchain * * @param amounts optional set of amounts to lookup + * @param unlocked whether to restrict instances to unlocked ones * * @return a set of amount/instances */ - std::map get_output_histogram(const std::vector &amounts) const; + std::map get_output_histogram(const std::vector &amounts, bool unlocked) const; /** * @brief perform a check on all key images in the blockchain diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 166d1ba9..90f7a843 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1126,7 +1126,7 @@ namespace cryptonote std::map histogram; try { - histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts); + histogram = m_core.get_blockchain_storage().get_output_histogram(req.amounts, req.unlocked); } catch (const std::exception &e) { diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 63167e24..89370a03 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -1071,11 +1071,13 @@ namespace cryptonote std::vector amounts; uint64_t min_count; uint64_t max_count; + bool unlocked; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amounts); KV_SERIALIZE(min_count); KV_SERIALIZE(max_count); + KV_SERIALIZE(unlocked); END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 43dedaf8..502d64c9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2238,7 +2238,7 @@ uint64_t wallet2::sanitize_fee_multiplier(uint64_t fee_multiplier) const // transactions will be required std::vector wallet2::create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector extra, bool trusted_daemon) { - const std::vector unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, trusted_daemon); + const std::vector unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, trusted_daemon); fee_multiplier = sanitize_fee_multiplier(fee_multiplier); @@ -3061,7 +3061,7 @@ std::vector wallet2::get_unspent_amounts_vector() return vector; } //---------------------------------------------------------------------------------------------------- -std::vector wallet2::select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon) +std::vector wallet2::select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool trusted_daemon) { epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); epee::json_rpc::response resp_t = AUTO_VAL_INIT(resp_t); @@ -3073,6 +3073,7 @@ std::vector wallet2::select_available_outputs_from_histogram(uint64_t co req_t.params.amounts = get_unspent_amounts_vector(); req_t.params.min_count = count; req_t.params.max_count = 0; + req_t.params.unlocked = unlocked; bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_unmixable_outputs"); @@ -3102,13 +3103,13 @@ std::vector wallet2::select_available_outputs_from_histogram(uint64_t co std::vector wallet2::select_available_unmixable_outputs(bool trusted_daemon) { // request all outputs with less than 3 instances - return select_available_outputs_from_histogram(3, false, trusted_daemon); + return select_available_outputs_from_histogram(3, false, true, trusted_daemon); } //---------------------------------------------------------------------------------------------------- std::vector wallet2::select_available_mixable_outputs(bool trusted_daemon) { // request all outputs with at least 3 instances, so we can use mixin 2 with - return select_available_outputs_from_histogram(3, true, trusted_daemon); + return select_available_outputs_from_histogram(3, true, true, trusted_daemon); } //---------------------------------------------------------------------------------------------------- std::vector wallet2::create_unmixable_sweep_transactions(bool trusted_daemon) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 62a3c503..9ff6c4e2 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -383,7 +383,7 @@ namespace tools std::string get_keys_file() const; std::string get_daemon_address() const; - std::vector select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon); + std::vector select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool trusted_daemon); std::vector select_available_outputs(const std::function &f); std::vector select_available_unmixable_outputs(bool trusted_daemon); std::vector select_available_mixable_outputs(bool trusted_daemon);