Bitcoin Core 31.99.0
P2P Digital Currency
coinselection.h
Go to the documentation of this file.
1// Copyright (c) 2017-present 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#ifndef BITCOIN_WALLET_COINSELECTION_H
6#define BITCOIN_WALLET_COINSELECTION_H
7
8#include <consensus/amount.h>
10#include <outputtype.h>
11#include <policy/feerate.h>
13#include <random.h>
14#include <util/check.h>
15#include <util/insert.h>
16#include <util/result.h>
17
18#include <optional>
19
20
21namespace wallet {
23inline constexpr CAmount CHANGE_LOWER{50'000};
25inline constexpr CAmount CHANGE_UPPER{1'000'000};
26
28struct COutput {
29private:
31 std::optional<CAmount> effective_value;
32
34 std::optional<CAmount> fee;
35
36public:
39
42
48 int depth;
49
52
55
61 bool safe;
62
64 int64_t time;
65
67 bool from_me;
68
71
74
75 COutput(const COutPoint& outpoint, const CTxOut& txout, int depth, int input_bytes, bool solvable, bool safe, int64_t time, bool from_me, const std::optional<CFeeRate> feerate = std::nullopt)
77 txout{txout},
78 depth{depth},
81 safe{safe},
82 time{time},
84 {
85 if (feerate) {
86 // base fee without considering potential unconfirmed ancestors
87 fee = input_bytes < 0 ? 0 : feerate.value().GetFee(input_bytes);
88 effective_value = txout.nValue - fee.value();
89 }
90 }
91
92 COutput(const COutPoint& outpoint, const CTxOut& txout, int depth, int input_bytes, bool solvable, bool safe, int64_t time, bool from_me, const CAmount fees)
94 {
95 // if input_bytes is unknown, then fees should be 0, if input_bytes is known, then the fees should be a positive integer or 0 (input_bytes known and fees = 0 only happens in the tests)
96 assert((input_bytes < 0 && fees == 0) || (input_bytes > 0 && fees >= 0));
97 fee = fees;
98 effective_value = txout.nValue - fee.value();
99 }
100
101 bool operator<(const COutput& rhs) const
102 {
103 return outpoint < rhs.outpoint;
104 }
105
106 void ApplyBumpFee(CAmount bump_fee)
107 {
108 assert(bump_fee >= 0);
109 ancestor_bump_fees = bump_fee;
110 assert(fee);
111 *fee += bump_fee;
112 // Note: assert(effective_value - bump_fee == nValue - fee.value());
113 effective_value = txout.nValue - fee.value();
114 }
115
117 {
118 assert(fee.has_value());
119 return fee.value();
120 }
121
123 {
124 assert(effective_value.has_value());
125 return effective_value.value();
126 }
127
128 bool HasEffectiveValue() const { return effective_value.has_value(); }
129};
130
174 std::optional<int> m_max_tx_weight{std::nullopt};
175
177 CAmount min_change_target, CFeeRate effective_feerate,
178 CFeeRate long_term_feerate, CFeeRate discard_feerate, int tx_noinputs_size, bool avoid_partial,
179 std::optional<int> max_tx_weight = std::nullopt)
183 m_min_change_target(min_change_target),
184 m_effective_feerate(effective_feerate),
185 m_long_term_feerate(long_term_feerate),
186 m_discard_feerate(discard_feerate),
188 m_avoid_partial_spends(avoid_partial),
189 m_max_tx_weight(max_tx_weight)
190 {
191 }
193 : rng_fast{rng_fast} {}
194};
195
200{
203 const int conf_mine;
205 const int conf_theirs;
207 const uint64_t max_ancestors;
210 const uint64_t max_cluster_count;
212 const bool m_include_partial_groups{false};
213
218
219 bool operator<(const CoinEligibilityFilter& other) const {
221 < std::tie(other.conf_mine, other.conf_theirs, other.max_ancestors, other.max_cluster_count, other.m_include_partial_groups);
222 }
223};
224
227{
229 std::vector<std::shared_ptr<COutput>> m_outputs;
233 bool m_from_me{true};
237 int m_depth{999};
240 size_t m_ancestors{0};
257 int m_weight{0};
258
259 OutputGroup() = default;
263 {}
264
265 void Insert(const std::shared_ptr<COutput>& output, size_t ancestors, size_t cluster_count);
266 bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const;
268};
269
270struct Groups {
271 // Stores 'OutputGroup' containing only positive UTXOs (value > 0).
272 std::vector<OutputGroup> positive_group;
273 // Stores 'OutputGroup' which may contain both positive and negative UTXOs.
274 std::vector<OutputGroup> mixed_group;
275};
276
279{
280 // Maps output type to output groups.
281 std::map<OutputType, Groups> groups_by_type;
282 // All inserted groups, no type distinction.
284
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.
287 void Push(const OutputGroup& group, OutputType type, bool insert_positive, bool insert_mixed);
288 // Different output types count
289 size_t TypesCount() { return groups_by_type.size(); }
290};
291
292typedef std::map<CoinEligibilityFilter, OutputGroupTypeMap> FilteredOutputGroups;
293
308[[nodiscard]] CAmount GenerateChangeTarget(CAmount payment_value, CAmount change_fee, FastRandomContext& rng);
309
310enum class SelectionAlgorithm : uint8_t
311{
312 BNB = 0,
313 KNAPSACK = 1,
314 SRD = 2,
315 CG = 3,
316 MANUAL = 4,
317};
318
319std::string GetAlgorithmName(SelectionAlgorithm algo);
320
322 bool operator()(const std::shared_ptr<COutput>& a, const std::shared_ptr<COutput>& b) const {
323 return *a < *b;
324 }
325};
326using OutputSet = std::set<std::shared_ptr<COutput>, OutputPtrComparator>;
327
329{
330private:
338 bool m_use_effective{false};
340 std::optional<CAmount> m_waste;
346 int m_weight{0};
349
350 template<typename T>
351 void InsertInputs(const T& inputs)
352 {
353 // Store sum of combined input sets to check that the results have no shared UTXOs
354 const size_t expected_count = m_selected_inputs.size() + inputs.size();
356 if (m_selected_inputs.size() != expected_count) {
357 throw std::runtime_error(STR_INTERNAL_BUG("Shared UTXOs among selection results"));
358 }
359 }
360
361public:
362 explicit SelectionResult(const CAmount target, SelectionAlgorithm algo)
363 : m_target(target), m_algo(algo) {}
364
365 SelectionResult() = delete;
366
368 [[nodiscard]] CAmount GetSelectedValue() const;
369
370 [[nodiscard]] CAmount GetSelectedEffectiveValue() const;
371
372 [[nodiscard]] CAmount GetTotalBumpFees() const;
373
374 void Clear();
375
376 void AddInput(const OutputGroup& group);
377 void AddInputs(const OutputSet& inputs, bool subtract_fee_outputs);
378
380 void SetBumpFeeDiscount(CAmount discount);
381
394 void RecalculateWaste(CAmount min_viable_change, CAmount change_cost, CAmount change_fee);
395 [[nodiscard]] CAmount GetWaste() const;
396
398 void SetAlgoCompleted(bool algo_completed);
399
401 bool GetAlgoCompleted() const;
402
404 void SetSelectionsEvaluated(size_t attempts);
405
407 size_t GetSelectionsEvaluated() const ;
408
415 void Merge(const SelectionResult& other);
416
418 const OutputSet& GetInputSet() const;
420 std::vector<std::shared_ptr<COutput>> GetShuffledInputVector() const;
421
422 bool operator<(SelectionResult other) const;
423
441 CAmount GetChange(CAmount min_viable_change, CAmount change_fee) const;
442
443 CAmount GetTarget() const { return m_target; }
444
446
447 int GetWeight() const { return m_weight; }
448};
449
450util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change,
451 int max_selection_weight);
452
453util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_selection_weight);
454
469util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng,
470 int max_selection_weight);
471
472// Original coin selection algorithm as a fallback
473util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
474 CAmount change_target, FastRandomContext& rng, int max_selection_weight);
475} // namespace wallet
476
477#endif // BITCOIN_WALLET_COINSELECTION_H
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
#define STR_INTERNAL_BUG(msg)
Definition: check.h:99
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
Definition: feerate.h:32
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
static constexpr uint32_t CURRENT_VERSION
Definition: transaction.h:284
An output of a transaction.
Definition: transaction.h:140
CAmount nValue
Definition: transaction.h:142
Fast randomness source.
Definition: random.h:386
@ MANUAL
We open manual connections to addresses that users explicitly requested via the addnode RPC or the -a...
void insert(Tdst &dst, const Tsrc &src)
Simplification of std insertion.
Definition: insert.h:14
constexpr CAmount CHANGE_UPPER
upper bound for randomly-chosen target change amount
Definition: coinselection.h:25
constexpr CAmount CHANGE_LOWER
lower bound for randomly-chosen target change amount
Definition: coinselection.h:23
util::Result< SelectionResult > SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, const CAmount &cost_of_change, int max_selection_weight)
SelectionAlgorithm
util::Result< SelectionResult > CoinGrinder(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, CAmount change_target, int max_selection_weight)
std::set< std::shared_ptr< COutput >, OutputPtrComparator > OutputSet
util::Result< SelectionResult > KnapsackSolver(std::vector< OutputGroup > &groups, const CAmount &nTargetValue, CAmount change_target, FastRandomContext &rng, int max_selection_weight)
CAmount GenerateChangeTarget(const CAmount payment_value, const CAmount change_fee, FastRandomContext &rng)
Choose a random change target for each transaction to make it harder to fingerprint the Core wallet b...
std::string GetAlgorithmName(const SelectionAlgorithm algo)
std::map< CoinEligibilityFilter, OutputGroupTypeMap > FilteredOutputGroups
util::Result< SelectionResult > SelectCoinsSRD(const std::vector< OutputGroup > &utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext &rng, int max_selection_weight)
Select coins by Single Random Draw (SRD).
OutputType
Definition: outputtype.h:18
A UTXO under consideration for use in funding a new transaction.
Definition: coinselection.h:28
CAmount long_term_fee
The fee required to spend this output at the consolidation feerate.
Definition: coinselection.h:70
bool from_me
Whether the transaction containing this output is sent from the owning wallet.
Definition: coinselection.h:67
COutPoint outpoint
The outpoint identifying this UTXO.
Definition: coinselection.h:38
std::optional< CAmount > effective_value
The output's value minus fees required to spend it and bump its unconfirmed ancestors to the target f...
Definition: coinselection.h:31
COutput(const COutPoint &outpoint, const CTxOut &txout, int depth, int input_bytes, bool solvable, bool safe, int64_t time, bool from_me, const std::optional< CFeeRate > feerate=std::nullopt)
Definition: coinselection.h:75
bool solvable
Whether we know how to spend this output, ignoring the lack of keys.
Definition: coinselection.h:54
int64_t time
The time of the transaction containing this output as determined by CWalletTx::nTimeSmart.
Definition: coinselection.h:64
int depth
Depth in block chain.
Definition: coinselection.h:48
bool safe
Whether this output is considered safe to spend.
Definition: coinselection.h:61
CTxOut txout
The output itself.
Definition: coinselection.h:41
COutput(const COutPoint &outpoint, const CTxOut &txout, int depth, int input_bytes, bool solvable, bool safe, int64_t time, bool from_me, const CAmount fees)
Definition: coinselection.h:92
CAmount ancestor_bump_fees
The fee necessary to bump this UTXO's ancestor transactions to the target feerate.
Definition: coinselection.h:73
CAmount GetFee() const
int input_bytes
Pre-computed estimated size of this output as a fully-signed input in a transaction.
Definition: coinselection.h:51
CAmount GetEffectiveValue() const
bool operator<(const COutput &rhs) const
bool HasEffectiveValue() const
void ApplyBumpFee(CAmount bump_fee)
std::optional< CAmount > fee
The fee required to spend this output at the transaction's target feerate and to bump its unconfirmed...
Definition: coinselection.h:34
Parameters for filtering which OutputGroups we may use in coin selection.
const uint64_t max_ancestors
Maximum number of unconfirmed ancestors aggregated across all UTXOs in an OutputGroup.
const bool m_include_partial_groups
When avoid_reuse=true and there are full groups (OUTPUT_GROUP_MAX_ENTRIES), whether or not to use any...
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_cluster_count, bool include_partial)
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors)
bool operator<(const CoinEligibilityFilter &other) const
const int conf_theirs
Minimum number of confirmations for outputs received from a different wallet.
const uint64_t max_cluster_count
Maximum cluster count that a single UTXO in the OutputGroup may have.
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_cluster_count)
const int conf_mine
Minimum number of confirmations for outputs that we sent to ourselves.
Parameters for one iteration of Coin Selection.
uint32_t m_version
The version of the transaction we are trying to create.
CoinSelectionParams(FastRandomContext &rng_fast, int change_output_size, int change_spend_size, CAmount min_change_target, CFeeRate effective_feerate, CFeeRate long_term_feerate, CFeeRate discard_feerate, int tx_noinputs_size, bool avoid_partial, std::optional< int > max_tx_weight=std::nullopt)
FastRandomContext & rng_fast
Randomness to use in the context of coin selection.
CAmount m_min_change_target
Mininmum change to target in Knapsack solver and CoinGrinder: select coins to cover the payment and a...
bool m_subtract_fee_outputs
Indicate that we are subtracting the fee from outputs.
CoinSelectionParams(FastRandomContext &rng_fast)
bool m_include_unsafe_inputs
When true, allow unsafe coins to be selected during Coin Selection.
CFeeRate m_effective_feerate
The targeted feerate of the transaction being built.
CAmount min_viable_change
Minimum amount for creating a change output.
int change_spend_size
Size of the input to spend a change output in virtual bytes.
CAmount m_cost_of_change
Cost of creating the change output + cost of spending the change output in the future.
CAmount m_change_fee
Cost of creating the change output.
int change_output_size
Size of a change output in bytes, determined by the output type.
CFeeRate m_long_term_feerate
The feerate estimate used to estimate an upper bound on what should be sufficient to spend the change...
CFeeRate m_discard_feerate
If the cost to spend a change output at the discard feerate exceeds its value, drop it to fees.
int tx_noinputs_size
Size of the transaction before coin selection, consisting of the header and recipient output(s),...
std::optional< int > m_max_tx_weight
The maximum weight for this transaction.
bool m_avoid_partial_spends
When true, always spend all (up to OUTPUT_GROUP_MAX_ENTRIES) or none of the outputs associated with t...
std::vector< OutputGroup > positive_group
std::vector< OutputGroup > mixed_group
A group of UTXOs paid to the same output script.
CFeeRate m_long_term_feerate
The feerate for spending a created change output eventually (i.e.
bool m_from_me
Whether the UTXOs were sent by the wallet to itself.
OutputGroup(const CoinSelectionParams &params)
CAmount m_value
The total value of the UTXOs in sum.
bool m_subtract_fee_outputs
Indicate that we are subtracting the fee from outputs.
size_t m_max_cluster_count
The maximum cluster count of a single UTXO in this output group.
void Insert(const std::shared_ptr< COutput > &output, size_t ancestors, size_t cluster_count)
CAmount GetSelectionAmount() const
int m_depth
The minimum number of confirmations the UTXOs in the group have.
int m_weight
Total weight of the UTXOs in this group.
bool EligibleForSpending(const CoinEligibilityFilter &eligibility_filter) const
CAmount effective_value
The value of the UTXOs after deducting the cost of spending them at the effective feerate.
size_t m_ancestors
The aggregated count of unconfirmed ancestors of all UTXOs in this group.
CAmount fee
The fee to spend these UTXOs at the effective feerate.
CAmount long_term_fee
The fee to spend these UTXOs at the long term feerate.
std::vector< std::shared_ptr< COutput > > m_outputs
The list of UTXOs contained in this output group.
Stores several 'Groups' whose were mapped by output type.
void Push(const OutputGroup &group, OutputType type, bool insert_positive, bool insert_mixed)
std::map< OutputType, Groups > groups_by_type
bool operator()(const std::shared_ptr< COutput > &a, const std::shared_ptr< COutput > &b) const
int m_weight
Total weight of the selected inputs.
bool operator<(SelectionResult other) const
size_t m_selections_evaluated
The count of selections that were evaluated by this coin selection attempt.
void AddInputs(const OutputSet &inputs, bool subtract_fee_outputs)
CAmount bump_fee_group_discount
How much individual inputs overestimated the bump fees for the shared ancestry.
CAmount GetChange(CAmount min_viable_change, CAmount change_fee) const
Get the amount for the change output after paying needed fees.
void Merge(const SelectionResult &other)
Combines the.
OutputSet m_selected_inputs
Set of inputs selected by the algorithm to use in the transaction.
size_t GetSelectionsEvaluated() const
Get selections_evaluated.
SelectionAlgorithm m_algo
The algorithm used to produce this result.
void SetBumpFeeDiscount(CAmount discount)
How much individual inputs overestimated the bump fees for shared ancestries.
bool GetAlgoCompleted() const
Get m_algo_completed.
void RecalculateWaste(CAmount min_viable_change, CAmount change_cost, CAmount change_fee)
Calculates and stores the waste for this result given the cost of change and the opportunity cost of ...
void AddInput(const OutputGroup &group)
CAmount GetSelectedEffectiveValue() const
CAmount GetTotalBumpFees() const
bool m_algo_completed
False if algorithm was cut short by hitting limit of attempts and solution is non-optimal.
const OutputSet & GetInputSet() const
Get m_selected_inputs.
CAmount m_target
The target the algorithm selected for.
void InsertInputs(const T &inputs)
void SetAlgoCompleted(bool algo_completed)
Tracks that algorithm was able to exhaustively search the entire combination space before hitting lim...
SelectionResult(const CAmount target, SelectionAlgorithm algo)
CAmount GetSelectedValue() const
Get the sum of the input values.
CAmount GetTarget() const
SelectionAlgorithm GetAlgo() const
std::optional< CAmount > m_waste
The computed waste.
bool m_use_effective
Whether the input values for calculations should be the effective value (true) or normal value (false...
void SetSelectionsEvaluated(size_t attempts)
Record the number of selections that were evaluated.
std::vector< std::shared_ptr< COutput > > GetShuffledInputVector() const
Get the vector of COutputs that will be used to fill in a CTransaction's vin.
CAmount GetWaste() const
FastRandomContext rng
Definition: dbwrapper.cpp:413
assert(!tx.IsCoinBase())