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 /src/wallet | |
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.
Diffstat (limited to 'src/wallet')
-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; |