Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2017-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <wallet/coinselection.h>7#include <common/system.h>8#include <consensus/amount.h>9#include <consensus/consensus.h>10#include <interfaces/chain.h>11#include <policy/feerate.h>12#include <util/check.h>13#include <util/log.h>14#include <util/moneystr.h>16#include <numeric>17#include <optional>18#include <queue>20namespace wallet {21// Common selection error across the algorithms22static util::Result<SelectionResult> ErrorMaxWeightExceeded()23{24return util::Error{_("The inputs size exceeds the maximum weight. "25"Please try sending a smaller amount or manually consolidating your wallet's UTXOs")};26}28// Sort by descending (effective) value prefer lower waste on tie29struct {30bool operator()(const OutputGroup& a, const OutputGroup& b) const31{32if (a.GetSelectionAmount() == b.GetSelectionAmount()) {33// Lower waste is better when effective_values are tied34return (a.fee - a.long_term_fee) < (b.fee - b.long_term_fee);35}36return a.GetSelectionAmount() > b.GetSelectionAmount();37}38} descending;40// Sort by descending (effective) value prefer lower weight on tie41struct {42bool operator()(const OutputGroup& a, const OutputGroup& b) const43{44if (a.GetSelectionAmount() == b.GetSelectionAmount()) {45// Sort lower weight to front on tied effective_value46return a.m_weight < b.m_weight;47}48return a.GetSelectionAmount() > b.GetSelectionAmount();49}50} descending_effval_weight;52/*53* This is the Branch and Bound Coin Selection algorithm designed by Murch. It searches for an input54* set that can pay for the spending target and does not exceed the spending target by more than the55* cost of creating and spending a change output. The algorithm uses a depth-first search on a binary56* tree. In the binary tree, each node corresponds to the inclusion or the omission of a UTXO. UTXOs57* are sorted by their effective values, tie-broken by their waste score, and the tree is explored deterministically per the inclusion58* branch first. For each new input set candidate, the algorithm checks whether the selection is within the target range.59* While the selection has not reached the target range, more UTXOs are included. When a selection's60* value exceeds the target range, the complete subtree deriving from this selection prefix can be omitted.61* At that point, the last included UTXO is deselected and the corresponding omission branch explored62* instead starting by adding the subsequent UTXO. The search ends after the complete tree has been searched or after a limited number of tries.63*64* The algorithm continues to search for better solutions after one solution has been found. The best65* solution is chosen by minimal waste score. The waste metric is defined as the cost to66* spend the current inputs at the given fee rate minus the long term expected cost to spend the67* inputs, plus the amount by which the selection exceeds the spending target (the "excess"):68*69* excess = selected_amount - target70* waste = inputs × (currentFeeRate - longTermFeeRate) + excess71*72* Note that this means that at fee rates higher than longTermFeeRate additional inputs increase the73* waste score, while at fee rates lower than longTermFeeRate additional inputs decrease the waste74* score.75*76* The algorithm uses the following optimizations:77* 1. Lookahead: The lookahead stores the total remaining effective value of the undecided UTXOs for78* every depth of the search tree. Whenever the currently selected amount plus the potential79* amount from the lookahead falls short of the target, we can immediately stop searching the80* subtree as no more input set candidates can be found in it.81* 2. Skip clones: When two UTXOs match in weight and effective value ("are clones"), naive82* exploration would cause redundant work: e.g., given the UTXOs A, A', and B, where A and A' are83* clones, naive exploration would combine (read underscore as omission):84* [{}, {A}, {A, A'}, {A, A', B}, {A, _, B}, {_, A'}, {_, A', B}, {_, _, B}].85* In this case the input set candidates {A} and {A'} as well as {A, B} and {A', B} are86* equivalent. It is sufficient to explore combinations that select either both UTXOs or the87* first UTXO. Whenever the first UTXO is omitted, we can also skip the clone as we have already88* explored a set of equivalent combination as the one we could generate with the second clone.89* Concretely, we skip a UTXO when its predecessor is omitted and the UTXO matches the90* effective value and the waste of the predecessor.91* 3. Skip similar UTXOs that are more wasteful: This search algorithm operates on the list of UTXOs92* sorted by effective value, tie-broken to prefer lower waste. This means that among two93* subsequent UTXOs with the same effective value, the second UTXO’s waste score will either be94* equal _or higher_ than the first UTXO’s. This allows us to apply the clone skipping idea more95* broadly: any combination with the second UTXO is equivalent _or worse_ than what we already96* combined with the first UTXO. We skip a UTXO if its predecessor is omitted and the predecessor97* matches in effective value.98*99* The Branch and Bound algorithm is described in detail in Murch's Master Thesis:100* https://murch.one/wp-content/uploads/2016/11/erhardt2016coinselection.pdf101*102* @param const std::vector<OutputGroup>& utxo_pool The set of UTXO groups that we are choosing from.103* These UTXO groups will be sorted in descending order by effective value and the OutputGroups'104* values are their effective values.105* @param const CAmount& selection_target This is the value that we want to select. It is the lower106* bound of the range.107* @param const CAmount& cost_of_change This is the cost of creating and spending a change output.108* This plus selection_target is the upper bound of the range.109* @param int max_selection_weight The maximum allowed weight for a selection result to be valid.110* @returns The result of this coin selection algorithm, or std::nullopt111*/113static const size_t TOTAL_TRIES = 100000;115util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change,116int max_selection_weight)117{118std::sort(utxo_pool.begin(), utxo_pool.end(), descending);119// The sum of UTXO amounts after this UTXO index, e.g. lookahead[5] = Σ(UTXO[6+].amount)120std::vector<CAmount> lookahead(utxo_pool.size());122// Calculate lookahead values, and check that there are sufficient funds123CAmount total_available = 0;124for (int index = static_cast<int>(utxo_pool.size()) - 1; index >= 0; --index) {125lookahead[index] = total_available;126// UTXOs with non-positive effective value must have been filtered127Assume(utxo_pool[index].GetSelectionAmount() > 0);128total_available += utxo_pool[index].GetSelectionAmount();129}131if (total_available < selection_target) {132// Insufficient funds133return util::Error();134}137// The current selection and the best input set found so far, stored as the utxo_pool indices of the UTXOs forming them138std::vector<size_t> curr_selection;139std::vector<size_t> best_selection;141// The currently selected effective amount142CAmount curr_amount = 0;144// The waste score of the current selection, and the best waste score so far145CAmount curr_selection_waste = 0;146CAmount best_waste = MAX_MONEY;148// The weight of the currently selected input set149int curr_weight = 0;151// Whether the input sets generated during this search have exceeded the maximum transaction weight at any point152bool max_tx_weight_exceeded = false;154// Index of the next UTXO to consider in utxo_pool155size_t next_utxo = 0;157auto deselect_last = [&]() {158OutputGroup& utxo = utxo_pool[curr_selection.back()];159curr_amount -= utxo.GetSelectionAmount();160curr_weight -= utxo.m_weight;161curr_selection_waste -= utxo.fee - utxo.long_term_fee;162curr_selection.pop_back();163};165size_t curr_try = 0;166SelectionResult result(selection_target, SelectionAlgorithm::BNB);167bool is_done = false;168// We don’t have access to the feerate here, but fee to long_term_fee is as feerate to LTFRE169bool is_feerate_high = utxo_pool.at(0).fee > utxo_pool.at(0).long_term_fee;170while (!is_done) {171bool should_shift{false}, should_cut{false};172// Select `next_utxo`173OutputGroup& utxo = utxo_pool[next_utxo];174curr_amount += utxo.GetSelectionAmount();175curr_weight += utxo.m_weight;176curr_selection_waste += utxo.fee - utxo.long_term_fee;177curr_selection.push_back(next_utxo);178++next_utxo;179++curr_try;181// EVALUATE current selection: check for solutions and see whether we can CUT or SHIFT before EXPLORING further182if (curr_amount + lookahead[curr_selection.back()] < selection_target) {183// Insufficient funds with lookahead: CUT184should_cut = true;185} else if (curr_weight > max_selection_weight) {186// max_weight exceeded: SHIFT187max_tx_weight_exceeded = true;188should_shift = true;189} else if (curr_amount > selection_target + cost_of_change) {190// Overshot target range: SHIFT191should_shift = true;192} else if (is_feerate_high && curr_selection_waste > best_waste) {193// At high feerates adding more inputs will increase the waste score. If the current waste is already worse194// than the best selection’s while we have insufficient funds, it is impossible for this partial selection195// to beat the best selection by adding more inputs: SHIFT196// At low feerates, additional inputs lower the waste score, and using this would cause us to skip exploring197// combinations with more inputs of lower amounts.198should_shift = true;199} else if (curr_amount >= selection_target) {200// Selection is within target window: potential solution201// Adding more UTXOs only increases fees and cannot be better: SHIFT202should_shift = true;203// The amount exceeding the selection_target (the "excess"), would be dropped to the fees: it is waste.204CAmount curr_excess = curr_amount - selection_target;205CAmount curr_waste = curr_selection_waste + curr_excess;206if (curr_waste <= best_waste) {207// New best solution208best_selection = curr_selection;209best_waste = curr_waste;210}211}213if (curr_try >= TOTAL_TRIES) {214// Solution is not guaranteed to be optimal if `curr_try` hit TOTAL_TRIES215result.SetAlgoCompleted(false);216break;217}219if (next_utxo == utxo_pool.size()) {220// Last added UTXO was end of UTXO pool, nothing left to add on inclusion or omission branch: CUT221should_cut = true;222}224if (should_cut) {225// Neither adding to the current selection nor exploring the omission branch of the last selected UTXO can226// find any solutions. Redirect to exploring the Omission branch of the penultimate selected UTXO (i.e.227// set `next_utxo` to one after the penultimate selected, then deselect the last two selected UTXOs)228deselect_last();229should_shift = true;230}232while (should_shift) {233if (curr_selection.empty()) {234// Exhausted search space before running into attempt limit235is_done = true;236result.SetAlgoCompleted(true);237break;238}239// Set `next_utxo` to one after last selected, then deselect last selected UTXO240next_utxo = curr_selection.back() + 1;241deselect_last();242should_shift = false;244// After SHIFTing to an omission branch, the `next_utxo` might have the same effective value as the245// UTXO we just omitted. Since lower waste is our tiebreaker on UTXOs with equal effective value for sorting, if it246// ties on the effective value, it _must_ have the same waste (i.e. be a "clone" of the prior UTXO) or a247// higher waste. If so, selecting `next_utxo` would produce an equivalent or worse248// selection as one we previously evaluated. In that case, increment `next_utxo` until we find a UTXO with a249// differing amount.250Assume(next_utxo < utxo_pool.size());