mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
Merge #17458: Refactor OutputGroup effective value calculations and filtering to occur within the struct
9adc2f80fc14f11ee2b1f989ee7be71b58481e6f Refactor OutputGroups to handle effective values, fees, and filtering (Andrew Chow) 7d07e864b8846be186648814a5aaf34269f914a3 Use real value when calculating OutputGroup value (Andrew Chow) Pull request description: Currently, the effective values and filtering for positive effective values is done outside of the OutputGroup. We should instead have functions in Outputgroup to do this and call those for each OutputGroup. So this PR does that. This makes future changes for effective values in coin selection much easier. ACKs for top commit: instagibbs: reACK 9adc2f80fc14f11ee2b1f989ee7be71b58481e6f fjahr: re-ACK 9adc2f80fc14f11ee2b1f989ee7be71b58481e6f meshcollider: Light code review ACK 9adc2f80fc14f11ee2b1f989ee7be71b58481e6f Tree-SHA512: 7445c94b7295b45bcd83a6f8a5c8f6961a89453fcc856335192d4b4a66aec7724513616b04e5111588ab208c89b311055399d6279cd9c4ce452aefb85f04b64a
This commit is contained in:
parent
6853849642
commit
51ff73a3d1
@ -4,6 +4,7 @@
|
||||
|
||||
#include <wallet/coinselection.h>
|
||||
|
||||
#include <policy/feerate.h>
|
||||
#include <util/system.h>
|
||||
#include <util/moneystr.h>
|
||||
|
||||
@ -365,7 +366,7 @@ bool KnapsackSolver(const CAmount& nTargetValue, std::vector<OutputGroup>& group
|
||||
void OutputGroup::Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants) {
|
||||
m_outputs.push_back(output);
|
||||
m_from_me &= from_me;
|
||||
m_value += output.effective_value;
|
||||
m_value += output.txout.nValue;
|
||||
m_depth = std::min(m_depth, depth);
|
||||
// ancestors here express the number of ancestors the new coin will end up having, which is
|
||||
// the sum, rather than the max; this will overestimate in the cases where multiple inputs
|
||||
@ -374,15 +375,19 @@ 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
|
||||
// coin itself; thus, this value is counted as the max, not the sum
|
||||
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) {
|
||||
auto it = m_outputs.begin();
|
||||
while (it != m_outputs.end() && it->outpoint != output.outpoint) ++it;
|
||||
if (it == m_outputs.end()) return it;
|
||||
m_value -= output.effective_value;
|
||||
m_value -= output.txout.nValue;
|
||||
effective_value -= output.effective_value;
|
||||
fee -= output.m_fee;
|
||||
long_term_fee -= output.m_long_term_fee;
|
||||
return m_outputs.erase(it);
|
||||
}
|
||||
|
||||
@ -401,3 +406,35 @@ bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_f
|
||||
&& m_ancestors <= eligibility_filter.max_ancestors
|
||||
&& 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 <random.h>
|
||||
|
||||
class CFeeRate;
|
||||
|
||||
//! target minimum change amount
|
||||
static constexpr CAmount MIN_CHANGE{COIN / 100};
|
||||
//! final minimum change amount after paying for fees
|
||||
@ -36,6 +38,8 @@ public:
|
||||
COutPoint outpoint;
|
||||
CTxOut txout;
|
||||
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 */
|
||||
int m_input_bytes{-1};
|
||||
@ -92,6 +96,10 @@ struct OutputGroup
|
||||
std::vector<CInputCoin>::iterator Discard(const CInputCoin& output);
|
||||
bool IsLockedByInstantSend() 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);
|
||||
|
@ -2745,27 +2745,15 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
|
||||
for (OutputGroup& group : groups) {
|
||||
if (!group.EligibleForSpending(eligibility_filter)) continue;
|
||||
|
||||
group.fee = 0;
|
||||
group.long_term_fee = 0;
|
||||
group.effective_value = 0;
|
||||
for (auto it = group.m_outputs.begin(); it != group.m_outputs.end(); ) {
|
||||
const CInputCoin& coin = *it;
|
||||
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 (coin_selection_params.m_subtract_fee_outputs) {
|
||||
// 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.SetFees(CFeeRate(0) /* effective_feerate */, long_term_feerate);
|
||||
} else {
|
||||
group.SetFees(coin_selection_params.effective_fee, long_term_feerate);
|
||||
}
|
||||
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
|
||||
CAmount not_input_fees = coin_selection_params.effective_fee.GetFee(coin_selection_params.tx_noinputs_size);
|
||||
|
Loading…
Reference in New Issue
Block a user