72    std::vector<bool> curr_selection; 
 
   73    curr_selection.reserve(utxo_pool.size());
 
   76    CAmount curr_available_value = 0;
 
   79        assert(utxo.GetSelectionAmount() > 0);
 
   80        curr_available_value += utxo.GetSelectionAmount();
 
   82    if (curr_available_value < selection_target) {
 
   87    std::sort(utxo_pool.begin(), utxo_pool.end(), 
descending);
 
   90    std::vector<bool> best_selection;
 
   96        bool backtrack = 
false;
 
   97        if (curr_value + curr_available_value < selection_target ||                
 
   98            curr_value > selection_target + cost_of_change ||    
 
   99            (curr_waste > best_waste && (utxo_pool.at(0).fee - utxo_pool.at(0).long_term_fee) > 0)) { 
 
  101        } 
else if (curr_value >= selection_target) {       
 
  102            curr_waste += (curr_value - selection_target); 
 
  107            if (curr_waste <= best_waste) {
 
  108                best_selection = curr_selection;
 
  109                best_selection.resize(utxo_pool.size());
 
  110                best_waste = curr_waste;
 
  111                if (best_waste == 0) {
 
  115            curr_waste -= (curr_value - selection_target); 
 
  122            while (!curr_selection.empty() && !curr_selection.back()) {
 
  123                curr_selection.pop_back();
 
  124                curr_available_value += utxo_pool.at(curr_selection.size()).GetSelectionAmount();
 
  127            if (curr_selection.empty()) { 
 
  132            curr_selection.back() = 
false;
 
  133            OutputGroup& utxo = utxo_pool.at(curr_selection.size() - 1);
 
  137            OutputGroup& utxo = utxo_pool.at(curr_selection.size());
 
  144            if (!curr_selection.empty() && !curr_selection.back() &&
 
  145                utxo.
GetSelectionAmount() == utxo_pool.at(curr_selection.size() - 1).GetSelectionAmount() &&
 
  146                utxo.
fee == utxo_pool.at(curr_selection.size() - 1).fee) {
 
  147                curr_selection.push_back(
false);
 
  150                curr_selection.push_back(
true);
 
  158    if (best_selection.empty()) {
 
  164    for (
size_t i = 0; i < best_selection.size(); ++i) {
 
  165        if (best_selection.at(i)) {
 
  167            value_ret += utxo_pool.at(i).m_value;
 
  176    std::set<CInputCoin> out_set;
 
  179    std::vector<size_t> indexes;
 
  180    indexes.resize(utxo_pool.size());
 
  181    std::iota(indexes.begin(), indexes.end(), 0);
 
  184    CAmount selected_eff_value = 0;
 
  185    for (
const size_t i : indexes) {
 
  191        if (selected_eff_value >= target_value) {
 
  192            return std::make_pair(out_set, value_ret);
 
  199                                  std::vector<char>& vfBest, 
CAmount& nBest, 
int iterations = 1000)
 
  201    std::vector<char> vfIncluded;
 
  203    vfBest.assign(groups.size(), 
true);
 
  208    for (
int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
 
  210        vfIncluded.assign(groups.size(), 
false);
 
  212        bool fReachedTarget = 
false;
 
  213        for (
int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
 
  215            for (
unsigned int i = 0; i < groups.size(); i++)
 
  223                if (nPass == 0 ? insecure_rand.
randbool() : !vfIncluded[i])
 
  225                    nTotal += groups[i].GetSelectionAmount();
 
  226                    vfIncluded[i] = 
true;
 
  227                    if (nTotal >= nTargetValue)
 
  229                        fReachedTarget = 
true;
 
  235                        nTotal -= groups[i].GetSelectionAmount();
 
  236                        vfIncluded[i] = 
false;
 
  250    std::optional<OutputGroup> lowest_larger;
 
  251    std::vector<OutputGroup> applicable_groups;
 
  257        if (group.GetSelectionAmount() == nTargetValue) {
 
  259            nValueRet += group.m_value;
 
  261        } 
else if (group.GetSelectionAmount() < nTargetValue + 
MIN_CHANGE) {
 
  262            applicable_groups.push_back(group);
 
  263            nTotalLower += group.GetSelectionAmount();
 
  264        } 
else if (!lowest_larger || group.GetSelectionAmount() < lowest_larger->GetSelectionAmount()) {
 
  265            lowest_larger = group;
 
  269    if (nTotalLower == nTargetValue) {
 
  270        for (
const auto& group : applicable_groups) {
 
  272            nValueRet += group.m_value;
 
  277    if (nTotalLower < nTargetValue) {
 
  278        if (!lowest_larger) 
return false;
 
  280        nValueRet += lowest_larger->m_value;
 
  285    std::sort(applicable_groups.begin(), applicable_groups.end(), 
descending);
 
  286    std::vector<char> vfBest;
 
  290    if (nBest != nTargetValue && nTotalLower >= nTargetValue + 
MIN_CHANGE) {
 
  297        ((nBest != nTargetValue && nBest < nTargetValue + 
MIN_CHANGE) || lowest_larger->GetSelectionAmount() <= nBest)) {
 
  299        nValueRet += lowest_larger->m_value;
 
  301        for (
unsigned int i = 0; i < applicable_groups.size(); i++) {
 
  303                util::insert(setCoinsRet, applicable_groups[i].m_outputs);
 
  304                nValueRet += applicable_groups[i].m_value;
 
  309            std::string log_message{
"Coin selection best subset: "};
 
  310            for (
unsigned int i = 0; i < applicable_groups.size(); i++) {
 
  334    if (positive_only && ev <= 0) 
return;
 
  339    coin.
m_fee = coin_fee;
 
  379    CAmount selected_effective_value = 0;
 
  381        waste += coin.m_fee - coin.m_long_term_fee;
 
  382        selected_effective_value += use_effective_value ? coin.effective_value : coin.txout.nValue;
 
  389        waste += change_cost;
 
  392        assert(selected_effective_value >= target);
 
  393        waste += selected_effective_value - target;
 
static constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
int64_t CAmount
Amount in satoshis (Can be negative)
#define Assume(val)
Assume is the identity function.
CAmount GetFee(uint32_t num_bytes) const
Return the fee in satoshis for the given size in bytes.
bool randbool() noexcept
Generate a random boolean.
bool KnapsackSolver(const CAmount &nTargetValue, std::vector< OutputGroup > &groups, std::set< CInputCoin > &setCoinsRet, CAmount &nValueRet)
std::optional< std::pair< std::set< CInputCoin >, CAmount > > SelectCoinsSRD(const std::vector< OutputGroup > &utxo_pool, CAmount target_value)
Select coins by Single Random Draw.
bool SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, const CAmount &cost_of_change, std::set< CInputCoin > &out_set, CAmount &value_ret)
static const size_t TOTAL_TRIES
static void ApproximateBestSubset(const std::vector< OutputGroup > &groups, const CAmount &nTotalLower, const CAmount &nTargetValue, std::vector< char > &vfBest, CAmount &nBest, int iterations=1000)
CAmount GetSelectionWaste(const std::set< CInputCoin > &inputs, CAmount change_cost, CAmount target, bool use_effective_value)
Compute the waste for this result given the cost of change and the opportunity cost of spending these...
static constexpr CAmount MIN_CHANGE
target minimum change amount
static bool LogAcceptCategory(BCLog::LogFlags category)
Return true if log accepts specified category.
#define LogPrint(category,...)
std::string FormatMoney(const CAmount n)
Money parsing/formatting utilities.
void insert(Tdst &dst, const Tsrc &src)
Simplification of std insertion.
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
Parameters for filtering which OutputGroups we may use in coin selection.
const int conf_mine
Minimum number of confirmations for outputs that we sent to ourselves.
const uint64_t max_ancestors
Maximum number of unconfirmed ancestors aggregated across all UTXOs in an OutputGroup.
const int conf_theirs
Minimum number of confirmations for outputs received from a different wallet.
const uint64_t max_descendants
Maximum number of descendants that a single UTXO in the OutputGroup may have.
A group of UTXOs paid to the same output script.
bool m_from_me
Whether the UTXOs were sent by the wallet to itself.
std::vector< CInputCoin > m_outputs
The list of UTXOs contained in this output group.
CAmount long_term_fee
The fee to spend these UTXOs at the long term feerate.
CFeeRate m_long_term_feerate
The feerate for spending a created change output eventually (i.e.
CAmount GetSelectionAmount() const
int m_depth
The minimum number of confirmations the UTXOs in the group have.
CFeeRate m_effective_feerate
The target feerate of the transaction we're trying to build.
size_t m_descendants
The maximum count of descendants of a single UTXO in this output group.
CAmount m_value
The total value of the UTXOs in sum.
void Insert(const CInputCoin &output, int depth, bool from_me, size_t ancestors, size_t descendants, bool positive_only)
size_t m_ancestors
The aggregated count of unconfirmed ancestors of all UTXOs in this group.
CAmount effective_value
The value of the UTXOs after deducting the cost of spending them at the effective feerate.
bool EligibleForSpending(const CoinEligibilityFilter &eligibility_filter) const
CAmount fee
The fee to spend these UTXOs at the effective feerate.
bool m_subtract_fee_outputs
Indicate that we are subtracting the fee from outputs.