diff options
author | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2017-01-14 17:18:14 +0000 |
---|---|---|
committer | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2017-01-14 21:43:01 +0000 |
commit | d276a16526d8ba752412c1588e6e8618c1f69d55 (patch) | |
tree | 349b88b7e6a1ce5da56c43329986bb45bb351264 | |
parent | Merge pull request #1562 (diff) | |
download | monero-d276a16526d8ba752412c1588e6e8618c1f69d55.tar.xz |
wallet2: use at least two rct inputs if possible
If we'd make a rct tx with just one input, we try to add
a second one to match the 2/2 ideal. This means more txes
use that template (and are thus using a larger anonymity
set), and it coalesces outputs "for free". We use the
smallest amount outputs in priority for this, so we can
"clean" the wallet at the same time.
-rw-r--r-- | src/wallet/wallet2.cpp | 41 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 4 |
2 files changed, 36 insertions, 9 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0ad74f52a..14a2eb112 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2733,7 +2733,7 @@ float wallet2::get_output_relatedness(const transfer_details &td0, const transfe return 0.0f; } //---------------------------------------------------------------------------------------------------- -size_t wallet2::pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_indices, const std::list<size_t>& selected_transfers) const +size_t wallet2::pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_indices, const std::list<size_t>& selected_transfers, bool smallest) const { std::vector<size_t> candidates; float best_relatedness = 1.0f; @@ -2761,13 +2761,30 @@ size_t wallet2::pop_best_value_from(const transfer_container &transfers, std::ve if (relatedness == best_relatedness) candidates.push_back(n); } - size_t idx = crypto::rand<size_t>() % candidates.size(); + + // we have all the least related outputs in candidates, so we can pick either + // the smallest, or a random one, depending on request + size_t idx; + if (smallest) + { + idx = 0; + for (size_t n = 0; n < candidates.size(); ++n) + { + const transfer_details &td = transfers[unused_indices[candidates[n]]]; + if (td.amount() < transfers[unused_indices[candidates[idx]]].amount()) + idx = n; + } + } + else + { + idx = crypto::rand<size_t>() % candidates.size(); + } return pop_index (unused_indices, candidates[idx]); } //---------------------------------------------------------------------------------------------------- -size_t wallet2::pop_best_value(std::vector<size_t> &unused_indices, const std::list<size_t>& selected_transfers) const +size_t wallet2::pop_best_value(std::vector<size_t> &unused_indices, const std::list<size_t>& selected_transfers, bool smallest) const { - return pop_best_value_from(m_transfers, unused_indices, selected_transfers); + return pop_best_value_from(m_transfers, unused_indices, selected_transfers, smallest); } //---------------------------------------------------------------------------------------------------- // Select random input sources for transaction. @@ -4109,8 +4126,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp } } - // while we have something to send - while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee) { + // while: + // - we have something to send + // - or we need to gather more fee + // - or we have just one input in that tx, which is rct (to try and make all/most rct txes 2/2) + while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || (use_rct && txes.back().selected_transfers.size() == 1)) { TX &tx = txes.back(); // if we need to spend money and don't have any left, we fail @@ -4121,7 +4141,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp // get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc) // This could be more clever, but maybe at the cost of making probabilistic inferences easier - size_t idx = !prefered_inputs.empty() ? pop_back(prefered_inputs) : !unused_transfers_indices.empty() ? pop_best_value(unused_transfers_indices, tx.selected_transfers) : pop_best_value(unused_dust_indices, tx.selected_transfers); + 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); + else if (!prefered_inputs.empty()) + idx = pop_back(prefered_inputs); + else + idx = pop_best_value(unused_transfers_indices.empty() ? unused_dust_indices : unused_transfers_indices, tx.selected_transfers); const transfer_details &td = m_transfers[idx]; LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount()) << ", ki " << td.m_key_image); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 7f25673d6..0d6d58844 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -527,8 +527,8 @@ namespace tools std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon); std::vector<size_t> select_available_mixable_outputs(bool trusted_daemon); - size_t pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_dust_indices, const std::list<size_t>& selected_transfers) const; - size_t pop_best_value(std::vector<size_t> &unused_dust_indices, const std::list<size_t>& selected_transfers) const; + size_t pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_dust_indices, const std::list<size_t>& selected_transfers, bool smallest = false) const; + size_t pop_best_value(std::vector<size_t> &unused_dust_indices, const std::list<size_t>& selected_transfers, bool smallest = false) const; void set_tx_note(const crypto::hash &txid, const std::string ¬e); std::string get_tx_note(const crypto::hash &txid) const; |