diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index dff848a9..e5788817 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -4120,7 +4120,7 @@ std::vector wallet2::pick_preferred_rct_inputs(uint64_t needed_money) co return picks; } -static bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector &unused_transfers_indices, const std::vector &unused_dust_indices) +bool wallet2::should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector &unused_transfers_indices, const std::vector &unused_dust_indices) const { if (!use_rct) return false; @@ -4128,9 +4128,43 @@ static bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const return false; if (unused_dust_indices.empty() && unused_transfers_indices.empty()) return false; + // we want at least one free rct output to avoid a corner case where + // we'd choose a non rct output which doesn't have enough "siblings" + // value-wise on the chain, and thus can't be mixed + bool found = false; + for (auto i: unused_dust_indices) + { + if (m_transfers[i].is_rct()) + { + found = true; + break; + } + } + if (!found) for (auto i: unused_transfers_indices) + { + if (m_transfers[i].is_rct()) + { + found = true; + break; + } + } + if (!found) + return false; return true; } +std::vector wallet2::get_only_rct(const std::vector &unused_dust_indices, const std::vector &unused_transfers_indices) const +{ + std::vector indices; + for (size_t n: unused_dust_indices) + if (m_transfers[n].is_rct()) + indices.push_back(n); + for (size_t n: unused_transfers_indices) + if (m_transfers[n].is_rct()) + indices.push_back(n); + return indices; +} + // Another implementation of transaction creation that is hopefully better // While there is anything left to pay, it goes through random outputs and tries // to fill the next destination/amount. If it fully fills it, it will use the @@ -4195,8 +4229,7 @@ std::vector wallet2::create_transactions_2(std::vector unused_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, true, trusted_daemon); - for (size_t i: unused_indices) + for (size_t i = 0; i < m_transfers.size(); ++i) { const transfer_details& td = m_transfers[i]; if (!td.m_spent && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td)) @@ -4279,7 +4312,8 @@ std::vector wallet2::create_transactions_2(std::vector indices = get_only_rct(unused_dust_indices, unused_transfers_indices); + idx = pop_best_value(indices, tx.selected_transfers, true); // since we're trying to add a second output which is not strictly needed, // we only add it if it's unrelated enough to the first one @@ -4289,6 +4323,8 @@ std::vector wallet2::create_transactions_2(std::vector> &outs, const std::list &selected_transfers, size_t fake_outputs_count); bool wallet_generate_key_image_helper(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki); crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const; + bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector &unused_transfers_indices, const std::vector &unused_dust_indices) const; + std::vector get_only_rct(const std::vector &unused_dust_indices, const std::vector &unused_transfers_indices) const; cryptonote::account_base m_account; boost::optional m_daemon_login;