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.
This commit is contained in:
parent
2806842200
commit
d276a16526
|
@ -2733,7 +2733,7 @@ float wallet2::get_output_relatedness(const transfer_details &td0, const transfe
|
||||||
return 0.0f;
|
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;
|
std::vector<size_t> candidates;
|
||||||
float best_relatedness = 1.0f;
|
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)
|
if (relatedness == best_relatedness)
|
||||||
candidates.push_back(n);
|
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]);
|
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.
|
// 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:
|
||||||
while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee) {
|
// - 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();
|
TX &tx = txes.back();
|
||||||
|
|
||||||
// if we need to spend money and don't have any left, we fail
|
// 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)
|
// 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
|
// 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];
|
const transfer_details &td = m_transfers[idx];
|
||||||
LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount()) << ", ki " << td.m_key_image);
|
LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount()) << ", ki " << td.m_key_image);
|
||||||
|
|
|
@ -527,8 +527,8 @@ namespace tools
|
||||||
std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon);
|
std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon);
|
||||||
std::vector<size_t> select_available_mixable_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_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) 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);
|
void set_tx_note(const crypto::hash &txid, const std::string ¬e);
|
||||||
std::string get_tx_note(const crypto::hash &txid) const;
|
std::string get_tx_note(const crypto::hash &txid) const;
|
||||||
|
|
Loading…
Reference in New Issue