mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-09 10:43:19 -05:00
wallet: ensure m_min_change_target always covers change fee
This commit is contained in:
parent
dc9d662683
commit
c8cf08ea74
4 changed files with 11 additions and 6 deletions
|
@ -389,14 +389,14 @@ CAmount GetSelectionWaste(const std::set<COutput>& inputs, CAmount change_cost,
|
||||||
return waste;
|
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) {
|
if (payment_value <= CHANGE_LOWER / 2) {
|
||||||
return CHANGE_LOWER;
|
return change_fee + CHANGE_LOWER;
|
||||||
} else {
|
} else {
|
||||||
// random value between 50ksat and min (payment_value * 2, 1milsat)
|
// random value between 50ksat and min (payment_value * 2, 1milsat)
|
||||||
const auto upper_bound = std::min(payment_value * 2, CHANGE_UPPER);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,6 +252,7 @@ struct OutputGroup
|
||||||
|
|
||||||
/** Choose a random change target for each transaction to make it harder to fingerprint the Core
|
/** 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.
|
* 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)
|
* The random value is between 50ksat and min(2 * payment_value, 1milsat)
|
||||||
* When payment_value <= 25ksat, the value is just 50ksat.
|
* 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).
|
* 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] 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
|
enum class SelectionAlgorithm : uint8_t
|
||||||
{
|
{
|
||||||
|
|
|
@ -794,7 +794,6 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
|
||||||
coin_selection_params.m_subtract_fee_outputs = true;
|
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
|
// Create change script that will be used if we need change
|
||||||
CScript scriptChange;
|
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_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_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
|
// vouts to the payees
|
||||||
if (!coin_selection_params.m_subtract_fee_outputs) {
|
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)
|
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)
|
||||||
|
|
|
@ -58,6 +58,8 @@ FUZZ_TARGET(coinselection)
|
||||||
coin_params.m_subtract_fee_outputs = subtract_fee_outputs;
|
coin_params.m_subtract_fee_outputs = subtract_fee_outputs;
|
||||||
coin_params.m_long_term_feerate = long_term_fee_rate;
|
coin_params.m_long_term_feerate = long_term_fee_rate;
|
||||||
coin_params.m_effective_feerate = effective_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
|
// Create some coins
|
||||||
CAmount total_balance{0};
|
CAmount total_balance{0};
|
||||||
|
@ -85,7 +87,7 @@ FUZZ_TARGET(coinselection)
|
||||||
auto result_srd = SelectCoinsSRD(group_pos, target, fast_random_context);
|
auto result_srd = SelectCoinsSRD(group_pos, target, fast_random_context);
|
||||||
if (result_srd) result_srd->ComputeAndSetWaste(cost_of_change);
|
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);
|
auto result_knapsack = KnapsackSolver(group_all, target, change_target, fast_random_context);
|
||||||
if (result_knapsack) result_knapsack->ComputeAndSetWaste(cost_of_change);
|
if (result_knapsack) result_knapsack->ComputeAndSetWaste(cost_of_change);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue