aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wallet/coinselection.cpp6
-rw-r--r--src/wallet/coinselection.h4
-rw-r--r--src/wallet/spend.cpp3
-rw-r--r--src/wallet/test/fuzz/coinselection.cpp4
4 files changed, 11 insertions, 6 deletions
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 49e6bac462..37cc7e37c8 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -389,14 +389,14 @@ CAmount GetSelectionWaste(const std::set<COutput>& inputs, CAmount change_cost,
return waste;
}
-CAmount GenerateChangeTarget(CAmount payment_value, FastRandomContext& rng)
+CAmount GenerateChangeTarget(const CAmount payment_value, const CAmount change_fee, FastRandomContext& rng)
{
if (payment_value <= CHANGE_LOWER / 2) {
- return CHANGE_LOWER;
+ return change_fee + CHANGE_LOWER;
} else {
// random value between 50ksat and min (payment_value * 2, 1milsat)
const auto upper_bound = std::min(payment_value * 2, CHANGE_UPPER);
- return rng.randrange(upper_bound - CHANGE_LOWER) + CHANGE_LOWER;
+ return change_fee + rng.randrange(upper_bound - CHANGE_LOWER) + CHANGE_LOWER;
}
}
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index e257d3f7c7..191476779f 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -252,6 +252,7 @@ struct OutputGroup
/** Choose a random change target for each transaction to make it harder to fingerprint the Core
* wallet based on the change output values of transactions it creates.
+ * Change target covers at least change fees and adds a random value on top of it.
* The random value is between 50ksat and min(2 * payment_value, 1milsat)
* When payment_value <= 25ksat, the value is just 50ksat.
*
@@ -261,8 +262,9 @@ struct OutputGroup
* coins selected are just sufficient to cover the payment amount ("unnecessary input" heuristic).
*
* @param[in] payment_value Average payment value of the transaction output(s).
+ * @param[in] change_fee Fee for creating a change output.
*/
-[[nodiscard]] CAmount GenerateChangeTarget(CAmount payment_value, FastRandomContext& rng);
+[[nodiscard]] CAmount GenerateChangeTarget(const CAmount payment_value, const CAmount change_fee, FastRandomContext& rng);
enum class SelectionAlgorithm : uint8_t
{
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 61d86844df..9babb5e04e 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -794,7 +794,6 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
coin_selection_params.m_subtract_fee_outputs = true;
}
}
- coin_selection_params.m_min_change_target = GenerateChangeTarget(std::floor(recipients_sum / vecSend.size()), rng_fast);
// Create change script that will be used if we need change
CScript scriptChange;
@@ -863,6 +862,8 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
coin_selection_params.m_change_fee = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.change_output_size);
coin_selection_params.m_cost_of_change = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size) + coin_selection_params.m_change_fee;
+ coin_selection_params.m_min_change_target = GenerateChangeTarget(std::floor(recipients_sum / vecSend.size()), coin_selection_params.m_change_fee, rng_fast);
+
// vouts to the payees
if (!coin_selection_params.m_subtract_fee_outputs) {
coin_selection_params.tx_noinputs_size = 10; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size)
diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp
index 3465f2f331..52bd74126d 100644
--- a/src/wallet/test/fuzz/coinselection.cpp
+++ b/src/wallet/test/fuzz/coinselection.cpp
@@ -58,6 +58,8 @@ FUZZ_TARGET(coinselection)
coin_params.m_subtract_fee_outputs = subtract_fee_outputs;
coin_params.m_long_term_feerate = long_term_fee_rate;
coin_params.m_effective_feerate = effective_fee_rate;
+ coin_params.change_output_size = fuzzed_data_provider.ConsumeIntegralInRange<int>(10, 1000);
+ coin_params.m_change_fee = effective_fee_rate.GetFee(coin_params.change_output_size);
// Create some coins
CAmount total_balance{0};
@@ -85,7 +87,7 @@ FUZZ_TARGET(coinselection)
auto result_srd = SelectCoinsSRD(group_pos, target, fast_random_context);
if (result_srd) result_srd->ComputeAndSetWaste(cost_of_change);
- CAmount change_target{GenerateChangeTarget(target, fast_random_context)};
+ CAmount change_target{GenerateChangeTarget(target, coin_params.m_change_fee, fast_random_context)};
auto result_knapsack = KnapsackSolver(group_all, target, change_target, fast_random_context);
if (result_knapsack) result_knapsack->ComputeAndSetWaste(cost_of_change);