Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/coinselection.cpp
// Copyright (c) 2017 The Bitcoin Core developers | // Copyright (c) 2017 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <wallet/coinselection.h> | #include <wallet/coinselection.h> | ||||
#include <feerate.h> | |||||
#include <util/moneystr.h> | #include <util/moneystr.h> | ||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <optional> | #include <optional> | ||||
// Descending order comparator | // Descending order comparator | ||||
struct { | struct { | ||||
bool operator()(const OutputGroup &a, const OutputGroup &b) const { | bool operator()(const OutputGroup &a, const OutputGroup &b) const { | ||||
▲ Show 20 Lines • Show All 340 Lines • ▼ Show 20 Lines | void OutputGroup::Insert(const CInputCoin &output, int depth, bool from_me, | ||||
// ancestors here express the number of ancestors the new coin will end up | // 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 | // having, which is the sum, rather than the max; this will overestimate in | ||||
// the cases where multiple inputs have common ancestors | // the cases where multiple inputs have common ancestors | ||||
m_ancestors += ancestors; | m_ancestors += ancestors; | ||||
// descendants is the count as seen from the top ancestor, not 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 | // descendants as seen from the coin itself; thus, this value is counted as | ||||
// the max, not the sum | // 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 | std::vector<CInputCoin>::iterator | ||||
OutputGroup::Discard(const CInputCoin &output) { | OutputGroup::Discard(const CInputCoin &output) { | ||||
auto it = m_outputs.begin(); | auto it = m_outputs.begin(); | ||||
while (it != m_outputs.end() && it->outpoint != output.outpoint) { | while (it != m_outputs.end() && it->outpoint != output.outpoint) { | ||||
++it; | ++it; | ||||
} | } | ||||
if (it == m_outputs.end()) { | if (it == m_outputs.end()) { | ||||
return it; | 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); | ||||
} | } | ||||
bool OutputGroup::EligibleForSpending( | bool OutputGroup::EligibleForSpending( | ||||
const CoinEligibilityFilter &eligibility_filter) const { | const CoinEligibilityFilter &eligibility_filter) const { | ||||
return m_depth >= (m_from_me ? eligibility_filter.conf_mine | return m_depth >= (m_from_me ? eligibility_filter.conf_mine | ||||
: eligibility_filter.conf_theirs) && | : eligibility_filter.conf_theirs) && | ||||
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 = Amount::zero(); | |||||
long_term_fee = Amount::zero(); | |||||
effective_value = Amount::zero(); | |||||
for (CInputCoin &coin : m_outputs) { | |||||
coin.m_fee = coin.m_input_bytes < 0 | |||||
? Amount::zero() | |||||
: effective_feerate.GetFee(coin.m_input_bytes); | |||||
fee += coin.m_fee; | |||||
coin.m_long_term_fee = | |||||
coin.m_input_bytes < 0 | |||||
? Amount::zero() | |||||
: 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 <= Amount::zero()) { | |||||
it = group.Discard(coin); | |||||
} else { | |||||
++it; | |||||
} | |||||
} | |||||
return group; | |||||
} |