LCOV - code coverage report
Current view: top level - src/wallet - coinselection.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 182 184 98.9 %
Date: 2020-09-26 01:30:44 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2017-2019 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <wallet/coinselection.h>
       6             : 
       7             : #include <optional.h>
       8             : #include <policy/feerate.h>
       9             : #include <util/system.h>
      10             : #include <util/moneystr.h>
      11             : 
      12             : // Descending order comparator
      13             : struct {
      14     4630760 :     bool operator()(const OutputGroup& a, const OutputGroup& b) const
      15             :     {
      16     4630760 :         return a.effective_value > b.effective_value;
      17             :     }
      18             : } descending;
      19             : 
      20             : /*
      21             :  * This is the Branch and Bound Coin Selection algorithm designed by Murch. It searches for an input
      22             :  * set that can pay for the spending target and does not exceed the spending target by more than the
      23             :  * cost of creating and spending a change output. The algorithm uses a depth-first search on a binary
      24             :  * tree. In the binary tree, each node corresponds to the inclusion or the omission of a UTXO. UTXOs
      25             :  * are sorted by their effective values and the trees is explored deterministically per the inclusion
      26             :  * branch first. At each node, the algorithm checks whether the selection is within the target range.
      27             :  * While the selection has not reached the target range, more UTXOs are included. When a selection's
      28             :  * value exceeds the target range, the complete subtree deriving from this selection can be omitted.
      29             :  * At that point, the last included UTXO is deselected and the corresponding omission branch explored
      30             :  * instead. The search ends after the complete tree has been searched or after a limited number of tries.
      31             :  *
      32             :  * The search continues to search for better solutions after one solution has been found. The best
      33             :  * solution is chosen by minimizing the waste metric. The waste metric is defined as the cost to
      34             :  * spend the current inputs at the given fee rate minus the long term expected cost to spend the
      35             :  * inputs, plus the amount the selection exceeds the spending target:
      36             :  *
      37             :  * waste = selectionTotal - target + inputs × (currentFeeRate - longTermFeeRate)
      38             :  *
      39             :  * The algorithm uses two additional optimizations. A lookahead keeps track of the total value of
      40             :  * the unexplored UTXOs. A subtree is not explored if the lookahead indicates that the target range
      41             :  * cannot be reached. Further, it is unnecessary to test equivalent combinations. This allows us
      42             :  * to skip testing the inclusion of UTXOs that match the effective value and waste of an omitted
      43             :  * predecessor.
      44             :  *
      45             :  * The Branch and Bound algorithm is described in detail in Murch's Master Thesis:
      46             :  * https://murch.one/wp-content/uploads/2016/11/erhardt2016coinselection.pdf
      47             :  *
      48             :  * @param const std::vector<CInputCoin>& utxo_pool The set of UTXOs that we are choosing from.
      49             :  *        These UTXOs will be sorted in descending order by effective value and the CInputCoins'
      50             :  *        values are their effective values.
      51             :  * @param const CAmount& target_value This is the value that we want to select. It is the lower
      52             :  *        bound of the range.
      53             :  * @param const CAmount& cost_of_change This is the cost of creating and spending a change output.
      54             :  *        This plus target_value is the upper bound of the range.
      55             :  * @param std::set<CInputCoin>& out_set -> This is an output parameter for the set of CInputCoins
      56             :  *        that have been selected.
      57             :  * @param CAmount& value_ret -> This is an output parameter for the total value of the CInputCoins
      58             :  *        that were selected.
      59             :  * @param CAmount not_input_fees -> The fees that need to be paid for the outputs and fixed size
      60             :  *        overhead (version, locktime, marker and flag)
      61             :  */
      62             : 
      63             : static const size_t TOTAL_TRIES = 100000;
      64             : 
      65       16657 : 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)
      66             : {
      67       16657 :     out_set.clear();
      68    79134216 :     CAmount curr_value = 0;
      69             : 
      70       16657 :     std::vector<bool> curr_selection; // select the utxo at this index
      71       16657 :     curr_selection.reserve(utxo_pool.size());
      72       16657 :     CAmount actual_target = not_input_fees + target_value;
      73             : 
      74             :     // Calculate curr_available_value
      75   158267663 :     CAmount curr_available_value = 0;
      76      850615 :     for (const OutputGroup& utxo : utxo_pool) {
      77             :         // Assert that this utxo is not negative. It should never be negative, effective value calculation should have removed it
      78      833958 :         assert(utxo.effective_value > 0);
      79      833958 :         curr_available_value += utxo.effective_value;
      80             :     }
      81       16657 :     if (curr_available_value < actual_target) {
      82         898 :         return false;
      83             :     }
      84             : 
      85             :     // Sort the utxo_pool
      86       15759 :     std::sort(utxo_pool.begin(), utxo_pool.end(), descending);
      87             : 
      88    79134216 :     CAmount curr_waste = 0;
      89       15759 :     std::vector<bool> best_selection;
      90    79134216 :     CAmount best_waste = MAX_MONEY;
      91             : 
      92             :     // Depth First search loop for choosing the UTXOs
      93    79134216 :     for (size_t i = 0; i < TOTAL_TRIES; ++i) {
      94             :         // Conditions for starting a backtrack
      95             :         bool backtrack = false;
      96    79133455 :         if (curr_value + curr_available_value < actual_target ||                // Cannot possibly reach target with the amount remaining in the curr_available_value.
      97    65994551 :             curr_value > actual_target + cost_of_change ||    // Selected value is out of range, go back and try other branch
      98    51983763 :             (curr_waste > best_waste && (utxo_pool.at(0).fee - utxo_pool.at(0).long_term_fee) > 0)) { // Don't select things which we know will be more wasteful if the waste is increasing
      99             :             backtrack = true;
     100    79133447 :         } else if (curr_value >= actual_target) {       // Selected value is within range
     101       43900 :             curr_waste += (curr_value - actual_target); // This is the excess value which is added to the waste for the below comparison
     102             :             // Adding another UTXO after this check could bring the waste down if the long term fee is higher than the current fee.
     103             :             // However we are not going to explore that because this optimization for the waste is only done when we have hit our target
     104             :             // value. Adding any more UTXOs will be just burning the UTXO; it will go entirely to fees. Thus we aren't going to
     105             :             // explore any more UTXOs to avoid burning money like that.
     106       43900 :             if (curr_waste <= best_waste) {
     107        2554 :                 best_selection = curr_selection;
     108        2554 :                 best_selection.resize(utxo_pool.size());
     109             :                 best_waste = curr_waste;
     110        2554 :                 if (best_waste == 0) {
     111         123 :                     break;
     112             :                 }
     113             :             }
     114             :             curr_waste -= (curr_value - actual_target); // Remove the excess value as we will be selecting different coins now
     115             :             backtrack = true;
     116       43777 :         }
     117             : 
     118             :         // Backtracking, moving backwards
     119    79133324 :         if (backtrack) {
     120             :             // Walk backwards to find the last included UTXO that still needs to have its omission branch traversed.
     121    78893422 :             while (!curr_selection.empty() && !curr_selection.back()) {
     122    51699961 :                 curr_selection.pop_back();
     123    51699961 :                 curr_available_value += utxo_pool.at(curr_selection.size()).effective_value;
     124             :             }
     125             : 
     126    27193461 :             if (curr_selection.empty()) { // We have walked back to the first utxo and no branch is untraversed. All solutions searched
     127       14867 :                 break;
     128             :             }
     129             : 
     130             :             // Output was included on previous iterations, try excluding now.
     131    27178594 :             curr_selection.back() = false;
     132    27178594 :             OutputGroup& utxo = utxo_pool.at(curr_selection.size() - 1);
     133    27178594 :             curr_value -= utxo.effective_value;
     134    27178594 :             curr_waste -= utxo.fee - utxo.long_term_fee;
     135    27178594 :         } else { // Moving forwards, continuing down this branch
     136    51939863 :             OutputGroup& utxo = utxo_pool.at(curr_selection.size());
     137             : 
     138             :             // Remove this utxo from the curr_available_value utxo amount
     139    51939863 :             curr_available_value -= utxo.effective_value;
     140             : 
     141             :             // Avoid searching a branch if the previous UTXO has the same value and same waste and was excluded. Since the ratio of fee to
     142             :             // long term fee is the same, we only need to check if one of those values match in order to know that the waste is the same.
     143    90701991 :             if (!curr_selection.empty() && !curr_selection.back() &&
     144    38762128 :                 utxo.effective_value == utxo_pool.at(curr_selection.size() - 1).effective_value &&
     145    24722883 :                 utxo.fee == utxo_pool.at(curr_selection.size() - 1).fee) {
     146    24722883 :                 curr_selection.push_back(false);
     147    24722883 :             } else {
     148             :                 // Inclusion branch first (Largest First Exploration)
     149    27216980 :                 curr_selection.push_back(true);
     150    27216980 :                 curr_value += utxo.effective_value;
     151    27216980 :                 curr_waste += utxo.fee - utxo.long_term_fee;
     152             :             }
     153           0 :         }
     154    79118457 :     }
     155             : 
     156             :     // Check for solution
     157       15759 :     if (best_selection.empty()) {
     158       15551 :         return false;
     159             :     }
     160             : 
     161             :     // Set output set
     162         208 :     value_ret = 0;
     163      161987 :     for (size_t i = 0; i < best_selection.size(); ++i) {
     164      161779 :         if (best_selection.at(i)) {
     165       24647 :             util::insert(out_set, utxo_pool.at(i).m_outputs);
     166       24647 :             value_ret += utxo_pool.at(i).m_value;
     167       24647 :         }
     168             :     }
     169             : 
     170         208 :     return true;
     171       16657 : }
     172             : 
     173        3530 : static void ApproximateBestSubset(const std::vector<OutputGroup>& groups, const CAmount& nTotalLower, const CAmount& nTargetValue,
     174             :                                   std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
     175             : {
     176        3530 :     std::vector<char> vfIncluded;
     177             : 
     178        3530 :     vfBest.assign(groups.size(), true);
     179        3530 :     nBest = nTotalLower;
     180             : 
     181        3530 :     FastRandomContext insecure_rand;
     182             : 
     183     2304794 :     for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
     184             :     {
     185     2301264 :         vfIncluded.assign(groups.size(), false);
     186     5753420 :         CAmount nTotal = 0;
     187     5753420 :         bool fReachedTarget = false;
     188     5753420 :         for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
     189             :         {
     190   373908257 :             for (unsigned int i = 0; i < groups.size(); i++)
     191             :             {
     192             :                 //The solver here uses a randomized algorithm,
     193             :                 //the randomness serves no real security purpose but is just
     194             :                 //needed to prevent degenerate behavior and it is important
     195             :                 //that the rng is fast. We do not use a constant random sequence,
     196             :                 //because there may be some privacy improvement by making
     197             :                 //the selection random.
     198   370456101 :                 if (nPass == 0 ? insecure_rand.randbool() : !vfIncluded[i])
     199             :                 {
     200   185693769 :                     nTotal += groups[i].m_value;
     201   185693769 :                     vfIncluded[i] = true;
     202   185693769 :                     if (nTotal >= nTargetValue)
     203             :                     {
     204             :                         fReachedTarget = true;
     205   170015126 :                         if (nTotal < nBest)
     206             :                         {
     207        7422 :                             nBest = nTotal;
     208        7422 :                             vfBest = vfIncluded;
     209             :                         }
     210   170015126 :                         nTotal -= groups[i].m_value;
     211   170015126 :                         vfIncluded[i] = false;
     212   170015126 :                     }
     213             :                 }
     214             :             }
     215             :         }
     216           0 :     }
     217        3530 : }
     218             : 
     219        8991 : bool KnapsackSolver(const CAmount& nTargetValue, std::vector<OutputGroup>& groups, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet)
     220             : {
     221        8991 :     setCoinsRet.clear();
     222        8991 :     nValueRet = 0;
     223             : 
     224             :     // List of values less than target
     225        8991 :     Optional<OutputGroup> lowest_larger;
     226        8991 :     std::vector<OutputGroup> applicable_groups;
     227        8991 :     CAmount nTotalLower = 0;
     228             : 
     229        8991 :     Shuffle(groups.begin(), groups.end(), FastRandomContext());
     230             : 
     231      596881 :     for (const OutputGroup& group : groups) {
     232      587890 :         if (group.m_value == nTargetValue) {
     233        1213 :             util::insert(setCoinsRet, group.m_outputs);
     234        1213 :             nValueRet += group.m_value;
     235        1213 :             return true;
     236      586677 :         } else if (group.m_value < nTargetValue + MIN_CHANGE) {
     237      259835 :             applicable_groups.push_back(group);
     238      259835 :             nTotalLower += group.m_value;
     239      586677 :         } else if (!lowest_larger || group.m_value < lowest_larger->m_value) {
     240        8064 :             lowest_larger = group;
     241             :         }
     242      586677 :     }
     243             : 
     244        7778 :     if (nTotalLower == nTargetValue) {
     245        2400 :         for (const auto& group : applicable_groups) {
     246        1900 :             util::insert(setCoinsRet, group.m_outputs);
     247        1900 :             nValueRet += group.m_value;
     248             :         }
     249         500 :         return true;
     250             :     }
     251             : 
     252        7278 :     if (nTotalLower < nTargetValue) {
     253        4935 :         if (!lowest_larger) return false;
     254        3497 :         util::insert(setCoinsRet, lowest_larger->m_outputs);
     255        3497 :         nValueRet += lowest_larger->m_value;
     256        3497 :         return true;
     257             :     }
     258             : 
     259             :     // Solve subset sum by stochastic approximation
     260        2343 :     std::sort(applicable_groups.begin(), applicable_groups.end(), descending);
     261        2343 :     std::vector<char> vfBest;
     262        2343 :     CAmount nBest;
     263             : 
     264        2343 :     ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue, vfBest, nBest);
     265        2343 :     if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) {
     266        1187 :         ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
     267        1187 :     }
     268             : 
     269             :     // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
     270             :     //                                   or the next bigger coin is closer), return the bigger coin
     271        3455 :     if (lowest_larger &&
     272        1219 :         ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || lowest_larger->m_value <= nBest)) {
     273         310 :         util::insert(setCoinsRet, lowest_larger->m_outputs);
     274         310 :         nValueRet += lowest_larger->m_value;
     275         310 :     } else {
     276      249027 :         for (unsigned int i = 0; i < applicable_groups.size(); i++) {
     277      246994 :             if (vfBest[i]) {
     278       93515 :                 util::insert(setCoinsRet, applicable_groups[i].m_outputs);
     279       93515 :                 nValueRet += applicable_groups[i].m_value;
     280       93515 :             }
     281             :         }
     282             : 
     283        2033 :         if (LogAcceptCategory(BCLog::SELECTCOINS)) {
     284        2033 :             LogPrint(BCLog::SELECTCOINS, "SelectCoins() best subset: "); /* Continued */
     285      249027 :             for (unsigned int i = 0; i < applicable_groups.size(); i++) {
     286      246994 :                 if (vfBest[i]) {
     287       93515 :                     LogPrint(BCLog::SELECTCOINS, "%s ", FormatMoney(applicable_groups[i].m_value)); /* Continued */
     288             :                 }
     289             :             }
     290        2033 :             LogPrint(BCLog::SELECTCOINS, "total %s\n", FormatMoney(nBest));
     291             :         }
     292             :     }
     293             : 
     294             :     return true;
     295        8991 : }
     296             : 
     297             : /******************************************************************************
     298             : 
     299             :  OutputGroup
     300             : 
     301             :  ******************************************************************************/
     302             : 
     303     1159490 : void OutputGroup::Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants) {
     304     1159490 :     m_outputs.push_back(output);
     305     1159490 :     m_from_me &= from_me;
     306     1159490 :     m_value += output.txout.nValue;
     307     1159490 :     m_depth = std::min(m_depth, depth);
     308             :     // ancestors here express the number of ancestors the new coin will end up having, which is
     309             :     // the sum, rather than the max; this will overestimate in the cases where multiple inputs
     310             :     // have common ancestors
     311     1159490 :     m_ancestors += ancestors;
     312             :     // descendants is the count as seen from the top ancestor, not the descendants as seen from the
     313             :     // coin itself; thus, this value is counted as the max, not the sum
     314     1159490 :     m_descendants = std::max(m_descendants, descendants);
     315     1159490 :     effective_value += output.effective_value;
     316     1159490 :     fee += output.m_fee;
     317     1159490 :     long_term_fee += output.m_long_term_fee;
     318     1159490 : }
     319             : 
     320          13 : std::vector<CInputCoin>::iterator OutputGroup::Discard(const CInputCoin& output) {
     321          13 :     auto it = m_outputs.begin();
     322          13 :     while (it != m_outputs.end() && it->outpoint != output.outpoint) ++it;
     323          13 :     if (it == m_outputs.end()) return it;
     324          13 :     m_value -= output.txout.nValue;
     325          13 :     effective_value -= output.effective_value;
     326          13 :     fee -= output.m_fee;
     327          13 :     long_term_fee -= output.m_long_term_fee;
     328          13 :     return m_outputs.erase(it);
     329          13 : }
     330             : 
     331     1507879 : bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const
     332             : {
     333     2987792 :     return m_depth >= (m_from_me ? eligibility_filter.conf_mine : eligibility_filter.conf_theirs)
     334     1507879 :         && m_ancestors <= eligibility_filter.max_ancestors
     335     1479913 :         && m_descendants <= eligibility_filter.max_descendants;
     336             : }
     337             : 
     338      781891 : void OutputGroup::SetFees(const CFeeRate effective_feerate, const CFeeRate long_term_feerate)
     339             : {
     340      781891 :     fee = 0;
     341      781891 :     long_term_fee = 0;
     342      781891 :     effective_value = 0;
     343     2043072 :     for (CInputCoin& coin : m_outputs) {
     344     1261181 :         coin.m_fee = coin.m_input_bytes < 0 ? 0 : effective_feerate.GetFee(coin.m_input_bytes);
     345     1261181 :         fee += coin.m_fee;
     346             : 
     347     1261181 :         coin.m_long_term_fee = coin.m_input_bytes < 0 ? 0 : long_term_feerate.GetFee(coin.m_input_bytes);
     348     1261181 :         long_term_fee += coin.m_long_term_fee;
     349             : 
     350     1261181 :         coin.effective_value = coin.txout.nValue - coin.m_fee;
     351     1261181 :         effective_value += coin.effective_value;
     352             :     }
     353      781891 : }
     354             : 
     355      781891 : OutputGroup OutputGroup::GetPositiveOnlyGroup()
     356             : {
     357      781891 :     OutputGroup group(*this);
     358     2043072 :     for (auto it = group.m_outputs.begin(); it != group.m_outputs.end(); ) {
     359     1261181 :         const CInputCoin& coin = *it;
     360             :         // Only include outputs that are positive effective value (i.e. not dust)
     361     1261181 :         if (coin.effective_value <= 0) {
     362          13 :             it = group.Discard(coin);
     363          13 :         } else {
     364     1261168 :             ++it;
     365             :         }
     366             :     }
     367             :     return group;
     368      781891 : }

Generated by: LCOV version 1.15