Skip to content

Commit 9adc2f8

Browse files
committed
Refactor OutputGroups to handle effective values, fees, and filtering
Instead of having callers set the fees, effective values, and filtering of outputs, do these within OutputGroups themselves as member functions. m_fee and m_long_term_fee is added to OutputGroup to track the fees of the OutputGroup.
1 parent 7d07e86 commit 9adc2f8

File tree

3 files changed

+54
-21
lines changed

3 files changed

+54
-21
lines changed

src/wallet/coinselection.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <wallet/coinselection.h>
66

77
#include <optional.h>
8+
#include <policy/feerate.h>
89
#include <util/system.h>
910
#include <util/moneystr.h>
1011

@@ -311,7 +312,9 @@ void OutputGroup::Insert(const CInputCoin& output, int depth, bool from_me, size
311312
// descendants is the count as seen from the top ancestor, not the descendants as seen from the
312313
// coin itself; thus, this value is counted as the max, not the sum
313314
m_descendants = std::max(m_descendants, descendants);
314-
effective_value = m_value;
315+
effective_value += output.effective_value;
316+
fee += output.m_fee;
317+
long_term_fee += output.m_long_term_fee;
315318
}
316319

317320
std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output) {
@@ -320,6 +323,8 @@ std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output)
320323
if (it == m_outputs.end()) return it;
321324
m_value -= output.txout.nValue;
322325
effective_value -= output.effective_value;
326+
fee -= output.m_fee;
327+
long_term_fee -= output.m_long_term_fee;
323328
return m_outputs.erase(it);
324329
}
325330

@@ -329,3 +334,35 @@ bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_f
329334
&& m_ancestors <= eligibility_filter.max_ancestors
330335
&& m_descendants <= eligibility_filter.max_descendants;
331336
}
337+
338+
void OutputGroup::SetFees(const CFeeRate effective_feerate, const CFeeRate long_term_feerate)
339+
{
340+
fee = 0;
341+
long_term_fee = 0;
342+
effective_value = 0;
343+
for (CInputCoin& coin : m_outputs) {
344+
coin.m_fee = coin.m_input_bytes < 0 ? 0 : effective_feerate.GetFee(coin.m_input_bytes);
345+
fee += coin.m_fee;
346+
347+
coin.m_long_term_fee = coin.m_input_bytes < 0 ? 0 : long_term_feerate.GetFee(coin.m_input_bytes);
348+
long_term_fee += coin.m_long_term_fee;
349+
350+
coin.effective_value = coin.txout.nValue - coin.m_fee;
351+
effective_value += coin.effective_value;
352+
}
353+
}
354+
355+
OutputGroup OutputGroup::GetPositiveOnlyGroup()
356+
{
357+
OutputGroup group(*this);
358+
for (auto it = group.m_outputs.begin(); it != group.m_outputs.end(); ) {
359+
const CInputCoin& coin = *it;
360+
// Only include outputs that are positive effective value (i.e. not dust)
361+
if (coin.effective_value <= 0) {
362+
it = group.Discard(coin);
363+
} else {
364+
++it;
365+
}
366+
}
367+
return group;
368+
}

src/wallet/coinselection.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <primitives/transaction.h>
1010
#include <random.h>
1111

12+
class CFeeRate;
13+
1214
//! target minimum change amount
1315
static constexpr CAmount MIN_CHANGE{COIN / 100};
1416
//! final minimum change amount after paying for fees
@@ -36,6 +38,8 @@ class CInputCoin {
3638
COutPoint outpoint;
3739
CTxOut txout;
3840
CAmount effective_value;
41+
CAmount m_fee{0};
42+
CAmount m_long_term_fee{0};
3943

4044
/** Pre-computed estimated size of this output as a fully-signed input in a transaction. Can be -1 if it could not be calculated */
4145
int m_input_bytes{-1};
@@ -91,6 +95,10 @@ struct OutputGroup
9195
void Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants);
9296
std::vector<CInputCoin>::iterator Discard(const CInputCoin& output);
9397
bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const;
98+
99+
//! Update the OutputGroup's fee, long_term_fee, and effective_value based on the given feerates
100+
void SetFees(const CFeeRate effective_feerate, const CFeeRate long_term_feerate);
101+
OutputGroup GetPositiveOnlyGroup();
94102
};
95103

96104
bool SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& target_value, const CAmount& cost_of_change, std::set<CInputCoin>& out_set, CAmount& value_ret, CAmount not_input_fees);

src/wallet/wallet.cpp

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2320,27 +2320,15 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
23202320
for (OutputGroup& group : groups) {
23212321
if (!group.EligibleForSpending(eligibility_filter)) continue;
23222322

2323-
group.fee = 0;
2324-
group.long_term_fee = 0;
2325-
group.effective_value = 0;
2326-
for (auto it = group.m_outputs.begin(); it != group.m_outputs.end(); ) {
2327-
const CInputCoin& coin = *it;
2328-
CAmount effective_value = coin.txout.nValue - (coin.m_input_bytes < 0 ? 0 : coin_selection_params.effective_fee.GetFee(coin.m_input_bytes));
2329-
// Only include outputs that are positive effective value (i.e. not dust)
2330-
if (effective_value > 0) {
2331-
group.fee += coin.m_input_bytes < 0 ? 0 : coin_selection_params.effective_fee.GetFee(coin.m_input_bytes);
2332-
group.long_term_fee += coin.m_input_bytes < 0 ? 0 : long_term_feerate.GetFee(coin.m_input_bytes);
2333-
if (coin_selection_params.m_subtract_fee_outputs) {
2334-
group.effective_value += coin.txout.nValue;
2335-
} else {
2336-
group.effective_value += effective_value;
2337-
}
2338-
++it;
2339-
} else {
2340-
it = group.Discard(coin);
2341-
}
2323+
if (coin_selection_params.m_subtract_fee_outputs) {
2324+
// Set the effective feerate to 0 as we don't want to use the effective value since the fees will be deducted from the output
2325+
group.SetFees(CFeeRate(0) /* effective_feerate */, long_term_feerate);
2326+
} else {
2327+
group.SetFees(coin_selection_params.effective_fee, long_term_feerate);
23422328
}
2343-
if (group.effective_value > 0) utxo_pool.push_back(group);
2329+
2330+
OutputGroup pos_group = group.GetPositiveOnlyGroup();
2331+
if (pos_group.effective_value > 0) utxo_pool.push_back(pos_group);
23442332
}
23452333
// Calculate the fees for things that aren't inputs
23462334
CAmount not_input_fees = coin_selection_params.effective_fee.GetFee(coin_selection_params.tx_noinputs_size);

0 commit comments

Comments
 (0)