Inside Bitcoin
Opening the selected file…
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.
251* it could be economical to create a change output. */252CFeeRate m_long_term_feerate{0};253/** Indicate that we are subtracting the fee from outputs.254* When true, the value that is used for coin selection is the UTXO's real value rather than effective value */255bool m_subtract_fee_outputs{false};256/** Total weight of the UTXOs in this group. */257int m_weight{0};259OutputGroup() = default;260OutputGroup(const CoinSelectionParams& params) :261m_long_term_feerate(params.m_long_term_feerate),262m_subtract_fee_outputs(params.m_subtract_fee_outputs)263{}265void Insert(const std::shared_ptr<COutput>& output, size_t ancestors, size_t cluster_count);266bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const;267CAmount GetSelectionAmount() const;268};270struct Groups {271// Stores 'OutputGroup' containing only positive UTXOs (value > 0).272std::vector<OutputGroup> positive_group;273// Stores 'OutputGroup' which may contain both positive and negative UTXOs.274std::vector<OutputGroup> mixed_group;275};277/** Stores several 'Groups' whose were mapped by output type. */278struct OutputGroupTypeMap279{280// Maps output type to output groups.281std::map<OutputType, Groups> groups_by_type;282// All inserted groups, no type distinction.283Groups all_groups;285// Based on the insert flag; appends group to the 'mixed_group' and, if value > 0, to the 'positive_group'.286// This affects both; the groups filtered by type and the overall groups container.287void Push(const OutputGroup& group, OutputType type, bool insert_positive, bool insert_mixed);288// Different output types count289size_t TypesCount() { return groups_by_type.size(); }290};292typedef std::map<CoinEligibilityFilter, OutputGroupTypeMap> FilteredOutputGroups;294/** Choose a random change target for each transaction to make it harder to fingerprint the Core295* wallet based on the change output values of transactions it creates.296* Change target covers at least change fees and adds a random value on top of it.297* The random value is between 50ksat and min(2 * payment_value, 1milsat)298* When payment_value <= 25ksat, the value is just 50ksat.299*300* Making change amounts similar to the payment value may help disguise which output(s) are payments301* are which ones are change. Using double the payment value may increase the number of inputs302* needed (and thus be more expensive in fees), but breaks analysis techniques which assume the303* coins selected are just sufficient to cover the payment amount ("unnecessary input" heuristic).304*305* @param[in] payment_value Average payment value of the transaction output(s).306* @param[in] change_fee Fee for creating a change output.307*/308[[nodiscard]] CAmount GenerateChangeTarget(CAmount payment_value, CAmount change_fee, FastRandomContext& rng);310enum class SelectionAlgorithm : uint8_t311{312BNB = 0,313KNAPSACK = 1,314SRD = 2,315CG = 3,316MANUAL = 4,317};319std::string GetAlgorithmName(SelectionAlgorithm algo);321struct OutputPtrComparator {322bool operator()(const std::shared_ptr<COutput>& a, const std::shared_ptr<COutput>& b) const {323return *a < *b;324}325};326using OutputSet = std::set<std::shared_ptr<COutput>, OutputPtrComparator>;328struct SelectionResult329{330private:331/** Set of inputs selected by the algorithm to use in the transaction */332OutputSet m_selected_inputs;333/** The target the algorithm selected for. Equal to the recipient amount plus non-input fees */334CAmount m_target;335/** The algorithm used to produce this result */336SelectionAlgorithm m_algo;337/** Whether the input values for calculations should be the effective value (true) or normal value (false) */338bool m_use_effective{false};339/** The computed waste */340std::optional<CAmount> m_waste;341/** False if algorithm was cut short by hitting limit of attempts and solution is non-optimal */342bool m_algo_completed{true};343/** The count of selections that were evaluated by this coin selection attempt */344size_t m_selections_evaluated;345/** Total weight of the selected inputs */346int m_weight{0};347/** How much individual inputs overestimated the bump fees for the shared ancestry */348CAmount bump_fee_group_discount{0};350template<typename T>351void InsertInputs(const T& inputs)352{353// Store sum of combined input sets to check that the results have no shared UTXOs354const size_t expected_count = m_selected_inputs.size() + inputs.size();355util::insert(m_selected_inputs, inputs);356if (m_selected_inputs.size() != expected_count) {357throw std::runtime_error(STR_INTERNAL_BUG("Shared UTXOs among selection results"));358}359}361public:362explicit SelectionResult(const CAmount target, SelectionAlgorithm algo)363: m_target(target), m_algo(algo) {}365SelectionResult() = delete;367/** Get the sum of the input values */368[[nodiscard]] CAmount GetSelectedValue() const;370[[nodiscard]] CAmount GetSelectedEffectiveValue() const;372[[nodiscard]] CAmount GetTotalBumpFees() const;374void Clear();376void AddInput(const OutputGroup& group);377void AddInputs(const OutputSet& inputs, bool subtract_fee_outputs);379/** How much individual inputs overestimated the bump fees for shared ancestries */380void SetBumpFeeDiscount(CAmount discount);382/** Calculates and stores the waste for this result given the cost of change383* and the opportunity cost of spending these inputs now vs in the future.384* If change exists, waste = change_cost + inputs * (effective_feerate - long_term_feerate) - bump_fee_group_discount385* If no change, waste = excess + inputs * (effective_feerate - long_term_feerate) - bump_fee_group_discount386* where excess = selected_effective_value - target387* change_cost = effective_feerate * change_output_size + long_term_feerate * change_spend_size388*389* @param[in] min_viable_change The minimum amount necessary to make a change output economic390* @param[in] change_cost The cost of creating a change output and spending it in the future. Only391* used if there is change, in which case it must be non-negative.392* @param[in] change_fee The fee for creating a change output393*/394void RecalculateWaste(CAmount min_viable_change, CAmount change_cost, CAmount change_fee);395[[nodiscard]] CAmount GetWaste() const;397/** Tracks that algorithm was able to exhaustively search the entire combination space before hitting limit of tries */398void SetAlgoCompleted(bool algo_completed);400/** Get m_algo_completed */401bool GetAlgoCompleted() const;403/** Record the number of selections that were evaluated */404void SetSelectionsEvaluated(size_t attempts);406/** Get selections_evaluated */407size_t GetSelectionsEvaluated() const ;409/**410* Combines the @param[in] other selection result into 'this' selection result.411*412* Important note:413* There must be no shared 'COutput' among the two selection results being combined.414*/415void Merge(const SelectionResult& other);417/** Get m_selected_inputs */418const OutputSet& GetInputSet() const;419/** Get the vector of COutputs that will be used to fill in a CTransaction's vin */420std::vector<std::shared_ptr<COutput>> GetShuffledInputVector() const;422bool operator<(SelectionResult other) const;424/** Get the amount for the change output after paying needed fees.425*426* The change amount is not 100% precise due to discrepancies in fee calculation.427* The final change amount (if any) should be corrected after calculating the final tx fees.428* When there is a discrepancy, most of the time the final change would be slightly bigger than estimated.429*430* Following are the possible factors of discrepancy:431* + non-input fees always include segwit flags432* + input fee estimation always include segwit stack size433* + input fees are rounded individually and not collectively, which leads to small rounding errors434* - input counter size is always assumed to be 1vbyte435*436* @param[in] min_viable_change Minimum amount for change output, if change would be less then we forgo change437* @param[in] change_fee Fees to include change output in the tx438* @returns Amount for change output, 0 when there is no change.439*440*/441CAmount GetChange(CAmount min_viable_change, CAmount change_fee) const;443CAmount GetTarget() const { return m_target; }445SelectionAlgorithm GetAlgo() const { return m_algo; }447int GetWeight() const { return m_weight; }448};450util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change,451int max_selection_weight);453util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_selection_weight);455/** Select coins by Single Random Draw (SRD). SRD selects eligible OutputGroups from a shuffled456* ordering until the effective value of the input set suffices to create the recipient outputs and a457* change output with an amount of at least CHANGE_LOWER. While the maximum selection458* weight is exceeded during selection, the OutputGroup with the lowest effective value is dropped459* from the selection before additional OutputGroups are selected. Due to this greedy approach,460* SRD can fail to discover possible solutions in pathological cases.461*462* @param[in] utxo_pool The positive effective value OutputGroups eligible for selection463* @param[in] target_value The target value to select for464* @param[in] change_fee The cost of adding the change output to the transaction at the transaction’s feerate.465* @param[in] rng The randomness source to shuffle coins466* @param[in] max_selection_weight The maximum allowed weight for a selection result to be valid467* @returns If successful, a valid SelectionResult, otherwise, util::Error468*/469util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng,470int max_selection_weight);472// Original coin selection algorithm as a fallback473util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,474CAmount change_target, FastRandomContext& rng, int max_selection_weight);475} // namespace wallet477#endif // BITCOIN_WALLET_COINSELECTION_H
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.