Skip to content

Commit 4f5ad43

Browse files
committed
Add waste metric calculation function
1 parent 935b3dd commit 4f5ad43

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

src/wallet/coinselection.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,30 @@ CAmount OutputGroup::GetSelectionAmount() const
341341
{
342342
return m_subtract_fee_outputs ? m_value : effective_value;
343343
}
344+
345+
CAmount GetSelectionWaste(const std::set<CInputCoin>& inputs, CAmount change_cost, CAmount target, bool use_effective_value)
346+
{
347+
// This function should not be called with empty inputs as that would mean the selection failed
348+
assert(!inputs.empty());
349+
350+
// Always consider the cost of spending an input now vs in the future.
351+
CAmount waste = 0;
352+
CAmount selected_effective_value = 0;
353+
for (const CInputCoin& coin : inputs) {
354+
waste += coin.m_fee - coin.m_long_term_fee;
355+
selected_effective_value += use_effective_value ? coin.effective_value : coin.txout.nValue;
356+
}
357+
358+
if (change_cost) {
359+
// Consider the cost of making change and spending it in the future
360+
// If we aren't making change, the caller should've set change_cost to 0
361+
assert(change_cost > 0);
362+
waste += change_cost;
363+
} else {
364+
// When we are not making change (change_cost == 0), consider the excess we are throwing away to fees
365+
assert(selected_effective_value >= target);
366+
waste += selected_effective_value - target;
367+
}
368+
369+
return waste;
370+
}

src/wallet/coinselection.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,21 @@ struct OutputGroup
166166
CAmount GetSelectionAmount() const;
167167
};
168168

169+
/** Compute the waste for this result given the cost of change
170+
* and the opportunity cost of spending these inputs now vs in the future.
171+
* If change exists, waste = change_cost + inputs * (effective_feerate - long_term_feerate)
172+
* If no change, waste = excess + inputs * (effective_feerate - long_term_feerate)
173+
* where excess = selected_effective_value - target
174+
* change_cost = effective_feerate * change_output_size + long_term_feerate * change_spend_size
175+
*
176+
* @param[in] inputs The selected inputs
177+
* @param[in] change_cost The cost of creating change and spending it in the future. Only used if there is change. Must be 0 if there is no change.
178+
* @param[in] target The amount targeted by the coin selection algorithm.
179+
* @param[in] use_effective_value Whether to use the input's effective value (when true) or the real value (when false).
180+
* @return The waste
181+
*/
182+
[[nodiscard]] CAmount GetSelectionWaste(const std::set<CInputCoin>& inputs, CAmount change_cost, CAmount target, bool use_effective_value = true);
183+
169184
bool SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change, std::set<CInputCoin>& out_set, CAmount& value_ret);
170185

171186
// Original coin selection algorithm as a fallback

0 commit comments

Comments
 (0)