aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wallet/coinselection.cpp27
-rw-r--r--src/wallet/coinselection.h15
2 files changed, 42 insertions, 0 deletions
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 25b1ee07e4..1699424657 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -341,3 +341,30 @@ CAmount OutputGroup::GetSelectionAmount() const
{
return m_subtract_fee_outputs ? m_value : effective_value;
}
+
+CAmount GetSelectionWaste(const std::set<CInputCoin>& inputs, CAmount change_cost, CAmount target, bool use_effective_value)
+{
+ // This function should not be called with empty inputs as that would mean the selection failed
+ assert(!inputs.empty());
+
+ // Always consider the cost of spending an input now vs in the future.
+ CAmount waste = 0;
+ CAmount selected_effective_value = 0;
+ for (const CInputCoin& coin : inputs) {
+ waste += coin.m_fee - coin.m_long_term_fee;
+ selected_effective_value += use_effective_value ? coin.effective_value : coin.txout.nValue;
+ }
+
+ if (change_cost) {
+ // Consider the cost of making change and spending it in the future
+ // If we aren't making change, the caller should've set change_cost to 0
+ assert(change_cost > 0);
+ waste += change_cost;
+ } else {
+ // When we are not making change (change_cost == 0), consider the excess we are throwing away to fees
+ assert(selected_effective_value >= target);
+ waste += selected_effective_value - target;
+ }
+
+ return waste;
+}
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index 7a3fb82139..35617d455b 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -166,6 +166,21 @@ struct OutputGroup
CAmount GetSelectionAmount() const;
};
+/** Compute the waste for this result given the cost of change
+ * and the opportunity cost of spending these inputs now vs in the future.
+ * If change exists, waste = change_cost + inputs * (effective_feerate - long_term_feerate)
+ * If no change, waste = excess + inputs * (effective_feerate - long_term_feerate)
+ * where excess = selected_effective_value - target
+ * change_cost = effective_feerate * change_output_size + long_term_feerate * change_spend_size
+ *
+ * @param[in] inputs The selected inputs
+ * @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.
+ * @param[in] target The amount targeted by the coin selection algorithm.
+ * @param[in] use_effective_value Whether to use the input's effective value (when true) or the real value (when false).
+ * @return The waste
+ */
+[[nodiscard]] CAmount GetSelectionWaste(const std::set<CInputCoin>& inputs, CAmount change_cost, CAmount target, bool use_effective_value = true);
+
bool SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change, std::set<CInputCoin>& out_set, CAmount& value_ret);
// Original coin selection algorithm as a fallback