mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-20 13:37:28 +02:00
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.
This commit is contained in:
parent
7d07e864b8
commit
9adc2f80fc
3 changed files with 54 additions and 21 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
#include <wallet/coinselection.h>
|
#include <wallet/coinselection.h>
|
||||||
|
|
||||||
#include <optional.h>
|
#include <optional.h>
|
||||||
|
#include <policy/feerate.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/moneystr.h>
|
#include <util/moneystr.h>
|
||||||
|
|
||||||
|
|
@ -311,7 +312,9 @@ void OutputGroup::Insert(const CInputCoin& output, int depth, bool from_me, size
|
||||||
// descendants is the count as seen from the top ancestor, not the descendants as seen from the
|
// descendants is the count as seen from the top ancestor, not the descendants as seen from the
|
||||||
// coin itself; thus, this value is counted as the max, not the sum
|
// coin itself; thus, this value is counted as the max, not the sum
|
||||||
m_descendants = std::max(m_descendants, descendants);
|
m_descendants = std::max(m_descendants, descendants);
|
||||||
effective_value = m_value;
|
effective_value += output.effective_value;
|
||||||
|
fee += output.m_fee;
|
||||||
|
long_term_fee += output.m_long_term_fee;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output) {
|
std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output) {
|
||||||
|
|
@ -320,6 +323,8 @@ std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output)
|
||||||
if (it == m_outputs.end()) return it;
|
if (it == m_outputs.end()) return it;
|
||||||
m_value -= output.txout.nValue;
|
m_value -= output.txout.nValue;
|
||||||
effective_value -= output.effective_value;
|
effective_value -= output.effective_value;
|
||||||
|
fee -= output.m_fee;
|
||||||
|
long_term_fee -= output.m_long_term_fee;
|
||||||
return m_outputs.erase(it);
|
return m_outputs.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -329,3 +334,35 @@ bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_f
|
||||||
&& m_ancestors <= eligibility_filter.max_ancestors
|
&& m_ancestors <= eligibility_filter.max_ancestors
|
||||||
&& m_descendants <= eligibility_filter.max_descendants;
|
&& m_descendants <= eligibility_filter.max_descendants;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutputGroup::SetFees(const CFeeRate effective_feerate, const CFeeRate long_term_feerate)
|
||||||
|
{
|
||||||
|
fee = 0;
|
||||||
|
long_term_fee = 0;
|
||||||
|
effective_value = 0;
|
||||||
|
for (CInputCoin& coin : m_outputs) {
|
||||||
|
coin.m_fee = coin.m_input_bytes < 0 ? 0 : effective_feerate.GetFee(coin.m_input_bytes);
|
||||||
|
fee += coin.m_fee;
|
||||||
|
|
||||||
|
coin.m_long_term_fee = coin.m_input_bytes < 0 ? 0 : long_term_feerate.GetFee(coin.m_input_bytes);
|
||||||
|
long_term_fee += coin.m_long_term_fee;
|
||||||
|
|
||||||
|
coin.effective_value = coin.txout.nValue - coin.m_fee;
|
||||||
|
effective_value += coin.effective_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputGroup OutputGroup::GetPositiveOnlyGroup()
|
||||||
|
{
|
||||||
|
OutputGroup group(*this);
|
||||||
|
for (auto it = group.m_outputs.begin(); it != group.m_outputs.end(); ) {
|
||||||
|
const CInputCoin& coin = *it;
|
||||||
|
// Only include outputs that are positive effective value (i.e. not dust)
|
||||||
|
if (coin.effective_value <= 0) {
|
||||||
|
it = group.Discard(coin);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <random.h>
|
#include <random.h>
|
||||||
|
|
||||||
|
class CFeeRate;
|
||||||
|
|
||||||
//! target minimum change amount
|
//! target minimum change amount
|
||||||
static constexpr CAmount MIN_CHANGE{COIN / 100};
|
static constexpr CAmount MIN_CHANGE{COIN / 100};
|
||||||
//! final minimum change amount after paying for fees
|
//! final minimum change amount after paying for fees
|
||||||
|
|
@ -36,6 +38,8 @@ public:
|
||||||
COutPoint outpoint;
|
COutPoint outpoint;
|
||||||
CTxOut txout;
|
CTxOut txout;
|
||||||
CAmount effective_value;
|
CAmount effective_value;
|
||||||
|
CAmount m_fee{0};
|
||||||
|
CAmount m_long_term_fee{0};
|
||||||
|
|
||||||
/** Pre-computed estimated size of this output as a fully-signed input in a transaction. Can be -1 if it could not be calculated */
|
/** Pre-computed estimated size of this output as a fully-signed input in a transaction. Can be -1 if it could not be calculated */
|
||||||
int m_input_bytes{-1};
|
int m_input_bytes{-1};
|
||||||
|
|
@ -91,6 +95,10 @@ struct OutputGroup
|
||||||
void Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants);
|
void Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants);
|
||||||
std::vector<CInputCoin>::iterator Discard(const CInputCoin& output);
|
std::vector<CInputCoin>::iterator Discard(const CInputCoin& output);
|
||||||
bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const;
|
bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const;
|
||||||
|
|
||||||
|
//! Update the OutputGroup's fee, long_term_fee, and effective_value based on the given feerates
|
||||||
|
void SetFees(const CFeeRate effective_feerate, const CFeeRate long_term_feerate);
|
||||||
|
OutputGroup GetPositiveOnlyGroup();
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
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);
|
||||||
|
|
|
||||||
|
|
@ -2320,27 +2320,15 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
|
||||||
for (OutputGroup& group : groups) {
|
for (OutputGroup& group : groups) {
|
||||||
if (!group.EligibleForSpending(eligibility_filter)) continue;
|
if (!group.EligibleForSpending(eligibility_filter)) continue;
|
||||||
|
|
||||||
group.fee = 0;
|
if (coin_selection_params.m_subtract_fee_outputs) {
|
||||||
group.long_term_fee = 0;
|
// 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
|
||||||
group.effective_value = 0;
|
group.SetFees(CFeeRate(0) /* effective_feerate */, long_term_feerate);
|
||||||
for (auto it = group.m_outputs.begin(); it != group.m_outputs.end(); ) {
|
} else {
|
||||||
const CInputCoin& coin = *it;
|
group.SetFees(coin_selection_params.effective_fee, long_term_feerate);
|
||||||
CAmount effective_value = coin.txout.nValue - (coin.m_input_bytes < 0 ? 0 : coin_selection_params.effective_fee.GetFee(coin.m_input_bytes));
|
|
||||||
// Only include outputs that are positive effective value (i.e. not dust)
|
|
||||||
if (effective_value > 0) {
|
|
||||||
group.fee += coin.m_input_bytes < 0 ? 0 : coin_selection_params.effective_fee.GetFee(coin.m_input_bytes);
|
|
||||||
group.long_term_fee += coin.m_input_bytes < 0 ? 0 : long_term_feerate.GetFee(coin.m_input_bytes);
|
|
||||||
if (coin_selection_params.m_subtract_fee_outputs) {
|
|
||||||
group.effective_value += coin.txout.nValue;
|
|
||||||
} else {
|
|
||||||
group.effective_value += effective_value;
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
} else {
|
|
||||||
it = group.Discard(coin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (group.effective_value > 0) utxo_pool.push_back(group);
|
|
||||||
|
OutputGroup pos_group = group.GetPositiveOnlyGroup();
|
||||||
|
if (pos_group.effective_value > 0) utxo_pool.push_back(pos_group);
|
||||||
}
|
}
|
||||||
// Calculate the fees for things that aren't inputs
|
// Calculate the fees for things that aren't inputs
|
||||||
CAmount not_input_fees = coin_selection_params.effective_fee.GetFee(coin_selection_params.tx_noinputs_size);
|
CAmount not_input_fees = coin_selection_params.effective_fee.GetFee(coin_selection_params.tx_noinputs_size);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue