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.
751nTotalLower += group.GetSelectionAmount();752} else if (!lowest_larger || group.GetSelectionAmount() < lowest_larger->GetSelectionAmount()) {753lowest_larger = group;754}755}757if (nTotalLower == nTargetValue) {758for (const auto& group : applicable_groups) {759result.AddInput(group);760}761if (result.GetWeight() <= max_selection_weight) return result;762else max_weight_exceeded = true;764// Try something else765result.Clear();766}768if (nTotalLower < nTargetValue) {769if (!lowest_larger) {770if (max_weight_exceeded) return ErrorMaxWeightExceeded();771return util::Error();772}773result.AddInput(*lowest_larger);774return result;775}777// Solve subset sum by stochastic approximation778std::sort(applicable_groups.begin(), applicable_groups.end(), descending);779std::vector<char> vfBest;780CAmount nBest;782ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue, vfBest, nBest, max_selection_weight);783if (nBest != nTargetValue && nTotalLower >= nTargetValue + change_target) {784ApproximateBestSubset(rng, applicable_groups, nTotalLower, nTargetValue + change_target, vfBest, nBest, max_selection_weight);785}787// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,788// or the next bigger coin is closer), return the bigger coin789if (lowest_larger &&790((nBest != nTargetValue && nBest < nTargetValue + change_target) || lowest_larger->GetSelectionAmount() <= nBest)) {791result.AddInput(*lowest_larger);792} else {793for (unsigned int i = 0; i < applicable_groups.size(); i++) {794if (vfBest[i]) {795result.AddInput(applicable_groups[i]);796}797}799// If the result exceeds the maximum allowed size, return closest UTXO above the target800if (result.GetWeight() > max_selection_weight) {801// No coin above target, nothing to do.802if (!lowest_larger) return ErrorMaxWeightExceeded();804// Return closest UTXO above target805result.Clear();806result.AddInput(*lowest_larger);807}809if (util::log::ShouldDebugLog(BCLog::SELECTCOINS)) {810std::string log_message{"Coin selection best subset: "};811for (unsigned int i = 0; i < applicable_groups.size(); i++) {812if (vfBest[i]) {813log_message += strprintf("%s ", FormatMoney(applicable_groups[i].m_value));814}815}816LogDebug(BCLog::SELECTCOINS, "%stotal %s\n", log_message, FormatMoney(nBest));817}818}819Assume(result.GetWeight() <= max_selection_weight);820return result;821}823/******************************************************************************825OutputGroup827******************************************************************************/829void OutputGroup::Insert(const std::shared_ptr<COutput>& output, size_t ancestors, size_t cluster_count) {830m_outputs.push_back(output);831auto& coin = *m_outputs.back();833fee += coin.GetFee();835coin.long_term_fee = coin.input_bytes < 0 ? 0 : m_long_term_feerate.GetFee(coin.input_bytes);836long_term_fee += coin.long_term_fee;838effective_value += coin.GetEffectiveValue();840m_from_me &= coin.from_me;841m_value += coin.txout.nValue;842m_depth = std::min(m_depth, coin.depth);843// ancestors here express the number of ancestors the new coin will end up having, which is844// the sum, rather than the max; this will overestimate in the cases where multiple inputs845// have common ancestors846m_ancestors += ancestors;847// This is the maximum cluster count among all outputs. If these outputs are from distinct clusters but spent in the848// same transaction, their clusters will be merged, potentially exceeding the mempool's max cluster count.849m_max_cluster_count = std::max(m_max_cluster_count, cluster_count);851if (output->input_bytes > 0) {852m_weight += output->input_bytes * WITNESS_SCALE_FACTOR;853}854}856bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const857{858return m_depth >= (m_from_me ? eligibility_filter.conf_mine : eligibility_filter.conf_theirs)859&& m_ancestors <= eligibility_filter.max_ancestors860&& m_max_cluster_count <= eligibility_filter.max_cluster_count;861}863CAmount OutputGroup::GetSelectionAmount() const864{865return m_subtract_fee_outputs ? m_value : effective_value;866}868void OutputGroupTypeMap::Push(const OutputGroup& group, OutputType type, bool insert_positive, bool insert_mixed)869{870if (group.m_outputs.empty()) return;872Groups& groups = groups_by_type[type];873if (insert_positive && group.GetSelectionAmount() > 0) {874groups.positive_group.emplace_back(group);875all_groups.positive_group.emplace_back(group);876}877if (insert_mixed) {878groups.mixed_group.emplace_back(group);879all_groups.mixed_group.emplace_back(group);880}881}883CAmount GenerateChangeTarget(const CAmount payment_value, const CAmount change_fee, FastRandomContext& rng)884{885if (payment_value <= CHANGE_LOWER / 2) {886return change_fee + CHANGE_LOWER;887} else {888// random value between 50ksat and min (payment_value * 2, 1milsat)889const auto upper_bound = std::min(payment_value * 2, CHANGE_UPPER);890return change_fee + rng.randrange(upper_bound - CHANGE_LOWER) + CHANGE_LOWER;891}892}894void SelectionResult::SetBumpFeeDiscount(const CAmount discount)895{896// Overlapping ancestry can only lower the fees, not increase them897assert (discount >= 0);898bump_fee_group_discount = discount;899}901void SelectionResult::RecalculateWaste(const CAmount min_viable_change, const CAmount change_cost, const CAmount change_fee)902{903// This function should not be called with empty inputs as that would mean the selection failed904assert(!m_selected_inputs.empty());906// Always consider the cost of spending an input now vs in the future.907CAmount waste = 0;908for (const auto& coin_ptr : m_selected_inputs) {909const COutput& coin = *coin_ptr;910waste += coin.GetFee() - coin.long_term_fee;911}912// Bump fee of whole selection may diverge from sum of individual bump fees913waste -= bump_fee_group_discount;915if (GetChange(min_viable_change, change_fee)) {916// if we have a minimum viable amount after deducting fees, account for917// cost of creating and spending change918waste += change_cost;919} else {920// When we are not making change (GetChange(…) == 0), consider the excess we are throwing away to fees921CAmount selected_effective_value = m_use_effective ? GetSelectedEffectiveValue() : GetSelectedValue();922assert(selected_effective_value >= m_target);923waste += selected_effective_value - m_target;924}926m_waste = waste;927}929void SelectionResult::SetAlgoCompleted(bool algo_completed)930{931m_algo_completed = algo_completed;932}934bool SelectionResult::GetAlgoCompleted() const935{936return m_algo_completed;937}939void SelectionResult::SetSelectionsEvaluated(size_t attempts)940{941m_selections_evaluated = attempts;942}944size_t SelectionResult::GetSelectionsEvaluated() const945{946return m_selections_evaluated;947}949CAmount SelectionResult::GetWaste() const950{951return *Assert(m_waste);952}954CAmount SelectionResult::GetSelectedValue() const955{956return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin->txout.nValue; });957}959CAmount SelectionResult::GetSelectedEffectiveValue() const960{961return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin->GetEffectiveValue(); }) + bump_fee_group_discount;962}964CAmount SelectionResult::GetTotalBumpFees() const965{966return std::accumulate(m_selected_inputs.cbegin(), m_selected_inputs.cend(), CAmount{0}, [](CAmount sum, const auto& coin) { return sum + coin->ancestor_bump_fees; }) - bump_fee_group_discount;967}969void SelectionResult::Clear()970{971m_selected_inputs.clear();972m_waste.reset();973m_weight = 0;974}976void SelectionResult::AddInput(const OutputGroup& group)977{978// As it can fail, combine inputs first979InsertInputs(group.m_outputs);980m_use_effective = !group.m_subtract_fee_outputs;982m_weight += group.m_weight;983}985void SelectionResult::AddInputs(const OutputSet& inputs, bool subtract_fee_outputs)986{987// As it can fail, combine inputs first988InsertInputs(inputs);989m_use_effective = !subtract_fee_outputs;991m_weight += std::accumulate(inputs.cbegin(), inputs.cend(), 0, [](int sum, const auto& coin) {992return sum + std::max(coin->input_bytes, 0) * WITNESS_SCALE_FACTOR;993});994}996void SelectionResult::Merge(const SelectionResult& other)997{998// As it can fail, combine inputs first999InsertInputs(other.m_selected_inputs);