Bitcoin Core  31.0.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>
9 #include <consensus/consensus.h>
10 #include <outputtype.h>
11 #include <policy/feerate.h>
12 #include <primitives/transaction.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 
21 namespace wallet {
23 static constexpr CAmount CHANGE_LOWER{50000};
25 static constexpr CAmount CHANGE_UPPER{1000000};
26 
28 struct COutput {
29 private:
31  std::optional<CAmount> effective_value;
32 
34  std::optional<CAmount> fee;
35 
36 public:
39 
42 
48  int depth;
49 
52 
54  bool solvable;
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)
76  : outpoint{outpoint},
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  std::string ToString() const;
102 
103  bool operator<(const COutput& rhs) const
104  {
105  return outpoint < rhs.outpoint;
106  }
107 
108  void ApplyBumpFee(CAmount bump_fee)
109  {
110  assert(bump_fee >= 0);
111  ancestor_bump_fees = bump_fee;
112  assert(fee);
113  *fee += bump_fee;
114  // Note: assert(effective_value - bump_fee == nValue - fee.value());
115  effective_value = txout.nValue - fee.value();
116  }
117 
118  CAmount GetFee() const
119  {
120  assert(fee.has_value());
121  return fee.value();
122  }
123 
125  {
126  assert(effective_value.has_value());
127  return effective_value.value();
128  }
129 
130  bool HasEffectiveValue() const { return effective_value.has_value(); }
131 };
132 
176  std::optional<int> m_max_tx_weight{std::nullopt};
177 
179  CAmount min_change_target, CFeeRate effective_feerate,
180  CFeeRate long_term_feerate, CFeeRate discard_feerate, int tx_noinputs_size, bool avoid_partial,
181  std::optional<int> max_tx_weight = std::nullopt)
182  : rng_fast{rng_fast},
185  m_min_change_target(min_change_target),
186  m_effective_feerate(effective_feerate),
187  m_long_term_feerate(long_term_feerate),
188  m_discard_feerate(discard_feerate),
190  m_avoid_partial_spends(avoid_partial),
191  m_max_tx_weight(max_tx_weight)
192  {
193  }
195  : rng_fast{rng_fast} {}
196 };
197 
202 {
205  const int conf_mine;
207  const int conf_theirs;
209  const uint64_t max_ancestors;
212  const uint64_t max_cluster_count;
214  const bool m_include_partial_groups{false};
215 
216  CoinEligibilityFilter() = delete;
220 
221  bool operator<(const CoinEligibilityFilter& other) const {
223  < std::tie(other.conf_mine, other.conf_theirs, other.max_ancestors, other.max_cluster_count, other.m_include_partial_groups);
224  }
225 };
226 
229 {
231  std::vector<std::shared_ptr<COutput>> m_outputs;
235  bool m_from_me{true};
239  int m_depth{999};
242  size_t m_ancestors{0};
259  int m_weight{0};
260 
261  OutputGroup() = default;
265  {}
266 
267  void Insert(const std::shared_ptr<COutput>& output, size_t ancestors, size_t cluster_count);
268  bool EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const;
269  CAmount GetSelectionAmount() const;
270 };
271 
272 struct Groups {
273  // Stores 'OutputGroup' containing only positive UTXOs (value > 0).
274  std::vector<OutputGroup> positive_group;
275  // Stores 'OutputGroup' which may contain both positive and negative UTXOs.
276  std::vector<OutputGroup> mixed_group;
277 };
278 
281 {
282  // Maps output type to output groups.
283  std::map<OutputType, Groups> groups_by_type;
284  // All inserted groups, no type distinction.
286 
287  // Based on the insert flag; appends group to the 'mixed_group' and, if value > 0, to the 'positive_group'.
288  // This affects both; the groups filtered by type and the overall groups container.
289  void Push(const OutputGroup& group, OutputType type, bool insert_positive, bool insert_mixed);
290  // Different output types count
291  size_t TypesCount() { return groups_by_type.size(); }
292 };
293 
294 typedef std::map<CoinEligibilityFilter, OutputGroupTypeMap> FilteredOutputGroups;
295 
310 [[nodiscard]] CAmount GenerateChangeTarget(CAmount payment_value, CAmount change_fee, FastRandomContext& rng);
311 
312 enum class SelectionAlgorithm : uint8_t
313 {
314  BNB = 0,
315  KNAPSACK = 1,
316  SRD = 2,
317  CG = 3,
318  MANUAL = 4,
319 };
320 
321 std::string GetAlgorithmName(SelectionAlgorithm algo);
322 
324  bool operator()(const std::shared_ptr<COutput>& a, const std::shared_ptr<COutput>& b) const {
325  return *a < *b;
326  }
327 };
328 using OutputSet = std::set<std::shared_ptr<COutput>, OutputPtrComparator>;
329 
331 {
332 private:
340  bool m_use_effective{false};
342  std::optional<CAmount> m_waste;
344  bool m_algo_completed{true};
348  int m_weight{0};
351 
352  template<typename T>
353  void InsertInputs(const T& inputs)
354  {
355  // Store sum of combined input sets to check that the results have no shared UTXOs
356  const size_t expected_count = m_selected_inputs.size() + inputs.size();
358  if (m_selected_inputs.size() != expected_count) {
359  throw std::runtime_error(STR_INTERNAL_BUG("Shared UTXOs among selection results"));
360  }
361  }
362 
363 public:
364  explicit SelectionResult(const CAmount target, SelectionAlgorithm algo)
365  : m_target(target), m_algo(algo) {}
366 
367  SelectionResult() = delete;
368 
370  [[nodiscard]] CAmount GetSelectedValue() const;
371 
372  [[nodiscard]] CAmount GetSelectedEffectiveValue() const;
373 
374  [[nodiscard]] CAmount GetTotalBumpFees() const;
375 
376  void Clear();
377 
378  void AddInput(const OutputGroup& group);
379  void AddInputs(const OutputSet& inputs, bool subtract_fee_outputs);
380 
382  void SetBumpFeeDiscount(CAmount discount);
383 
396  void RecalculateWaste(CAmount min_viable_change, CAmount change_cost, CAmount change_fee);
397  [[nodiscard]] CAmount GetWaste() const;
398 
400  void SetAlgoCompleted(bool algo_completed);
401 
403  bool GetAlgoCompleted() const;
404 
406  void SetSelectionsEvaluated(size_t attempts);
407 
409  size_t GetSelectionsEvaluated() const ;
410 
417  void Merge(const SelectionResult& other);
418 
420  const OutputSet& GetInputSet() const;
422  std::vector<std::shared_ptr<COutput>> GetShuffledInputVector() const;
423 
424  bool operator<(SelectionResult other) const;
425 
443  CAmount GetChange(CAmount min_viable_change, CAmount change_fee) const;
444 
445  CAmount GetTarget() const { return m_target; }
446 
447  SelectionAlgorithm GetAlgo() const { return m_algo; }
448 
449  int GetWeight() const { return m_weight; }
450 };
451 
452 util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change,
453  int max_selection_weight);
454 
455 util::Result<SelectionResult> CoinGrinder(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, CAmount change_target, int max_selection_weight);
456 
471 util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng,
472  int max_selection_weight);
473 
474 // Original coin selection algorithm as a fallback
475 util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
476  CAmount change_target, FastRandomContext& rng, int max_selection_weight);
477 } // namespace wallet
478 
479 #endif // BITCOIN_WALLET_COINSELECTION_H
CAmount nValue
Definition: transaction.h:142
bool m_subtract_fee_outputs
Indicate that we are subtracting the fee from outputs.
COutPoint outpoint
The outpoint identifying this UTXO.
Definition: coinselection.h:38
bool solvable
Whether we know how to spend this output, ignoring the lack of keys.
Definition: coinselection.h:54
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...
CAmount GetWaste() const
FastRandomContext & rng_fast
Randomness to use in the context of coin selection.
util::Result< SelectionResult > KnapsackSolver(std::vector< OutputGroup > &groups, const CAmount &nTargetValue, CAmount change_target, FastRandomContext &rng, int max_selection_weight)
CAmount m_value
The total value of the UTXOs in sum.
CAmount min_viable_change
Minimum amount for creating a change output.
CAmount GetEffectiveValue() const
std::map< OutputType, Groups > groups_by_type
const OutputSet & GetInputSet() const
Get m_selected_inputs.
Stores several &#39;Groups&#39; whose were mapped by output type.
assert(!tx.IsCoinBase())
CAmount fee
The fee to spend these UTXOs at the effective feerate.
size_t m_ancestors
The aggregated count of unconfirmed ancestors of all UTXOs in this group.
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_cluster_count, bool include_partial)
int tx_noinputs_size
Size of the transaction before coin selection, consisting of the header and recipient output(s)...
void AddInput(const OutputGroup &group)
void Insert(const std::shared_ptr< COutput > &output, size_t ancestors, size_t cluster_count)
const uint64_t max_ancestors
Maximum number of unconfirmed ancestors aggregated across all UTXOs in an OutputGroup.
int64_t time
The time of the transaction containing this output as determined by CWalletTx::nTimeSmart.
Definition: coinselection.h:64
int m_weight
Total weight of the UTXOs in this group.
static constexpr CAmount CHANGE_LOWER
lower bound for randomly-chosen target change amount
Definition: coinselection.h:23
CoinSelectionParams(FastRandomContext &rng_fast)
void ApplyBumpFee(CAmount bump_fee)
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors)
void insert(Tdst &dst, const Tsrc &src)
Simplification of std insertion.
Definition: insert.h:14
bool operator<(SelectionResult other) const
bool m_use_effective
Whether the input values for calculations should be the effective value (true) or normal value (false...
uint32_t m_version
The version of the transaction we are trying to create.
void SetSelectionsEvaluated(size_t attempts)
Record the number of selections that were evaluated.
CAmount GetChange(CAmount min_viable_change, CAmount change_fee) const
Get the amount for the change output after paying needed fees.
OutputType
Definition: outputtype.h:18
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)
OutputSet m_selected_inputs
Set of inputs selected by the algorithm to use in the transaction.
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
size_t m_selections_evaluated
The count of selections that were evaluated by this coin selection attempt.
util::Result< SelectionResult > CoinGrinder(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, CAmount change_target, int max_selection_weight)
CAmount effective_value
The value of the UTXOs after deducting the cost of spending them at the effective feerate...
int change_output_size
Size of a change output in bytes, determined by the output type.
void Push(const OutputGroup &group, OutputType type, bool insert_positive, bool insert_mixed)
SelectionAlgorithm
CTxOut txout
The output itself.
Definition: coinselection.h:41
CAmount GetTarget() const
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
CAmount bump_fee_group_discount
How much individual inputs overestimated the bump fees for the shared ancestry.
bool safe
Whether this output is considered safe to spend.
Definition: coinselection.h:61
bool operator<(const CoinEligibilityFilter &other) const
static const uint32_t CURRENT_VERSION
Definition: transaction.h:284
void AddInputs(const OutputSet &inputs, bool subtract_fee_outputs)
CFeeRate m_effective_feerate
The targeted feerate of the transaction being built.
std::string ToString() const
CAmount long_term_fee
The fee required to spend this output at the consolidation feerate.
Definition: coinselection.h:70
CAmount GetTotalBumpFees() const
bool EligibleForSpending(const CoinEligibilityFilter &eligibility_filter) const
CAmount m_min_change_target
Mininmum change to target in Knapsack solver and CoinGrinder: select coins to cover the payment and a...
bool from_me
Whether the transaction containing this output is sent from the owning wallet.
Definition: coinselection.h:67
size_t GetSelectionsEvaluated() const
Get selections_evaluated.
std::vector< OutputGroup > positive_group
CAmount GetSelectedEffectiveValue() const
std::optional< CAmount > fee
The fee required to spend this output at the transaction&#39;s target feerate and to bump its unconfirmed...
Definition: coinselection.h:34
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).
SelectionAlgorithm GetAlgo() const
std::optional< CAmount > m_waste
The computed waste.
int depth
Depth in block chain.
Definition: coinselection.h:48
Fast randomness source.
Definition: random.h:385
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_long_term_feerate
The feerate for spending a created change output eventually (i.e.
CFeeRate m_discard_feerate
If the cost to spend a change output at the discard feerate exceeds its value, drop it to fees...
CAmount m_cost_of_change
Cost of creating the change output + cost of spending the change output in the future.
bool operator()(const std::shared_ptr< COutput > &a, const std::shared_ptr< COutput > &b) const
bool HasEffectiveValue() const
CAmount GetSelectionAmount() const
SelectionAlgorithm m_algo
The algorithm used to produce this result.
An output of a transaction.
Definition: transaction.h:139
A group of UTXOs paid to the same output script.
void InsertInputs(const T &inputs)
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
bool m_avoid_partial_spends
When true, always spend all (up to OUTPUT_GROUP_MAX_ENTRIES) or none of the outputs associated with t...
int m_weight
Total weight of the selected inputs.
Parameters for one iteration of Coin Selection.
std::vector< std::shared_ptr< COutput > > m_outputs
The list of UTXOs contained in this output group.
util::Result< SelectionResult > SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, const CAmount &cost_of_change, int max_selection_weight)
bool m_subtract_fee_outputs
Indicate that we are subtracting the fee from outputs.
CoinEligibilityFilter(int conf_mine, int conf_theirs, uint64_t max_ancestors, uint64_t max_cluster_count)
std::set< std::shared_ptr< COutput >, OutputPtrComparator > OutputSet
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 ...
Parameters for filtering which OutputGroups we may use in coin selection.
bool m_include_unsafe_inputs
When true, allow unsafe coins to be selected during Coin Selection.
std::vector< OutputGroup > mixed_group
const int conf_mine
Minimum number of confirmations for outputs that we sent to ourselves.
std::optional< int > m_max_tx_weight
The maximum weight for this transaction.
int input_bytes
Pre-computed estimated size of this output as a fully-signed input in a transaction.
Definition: coinselection.h:51
SelectionResult(const CAmount target, SelectionAlgorithm algo)
int m_depth
The minimum number of confirmations the UTXOs in the group have.
void SetBumpFeeDiscount(CAmount discount)
How much individual inputs overestimated the bump fees for shared ancestries.
OutputGroup(const CoinSelectionParams &params)
std::string GetAlgorithmName(const SelectionAlgorithm algo)
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac...
Definition: feerate.h:31
CAmount GetFee() const
CAmount GetSelectedValue() const
Get the sum of the input values.
#define STR_INTERNAL_BUG(msg)
Definition: check.h:96
CAmount long_term_fee
The fee to spend these UTXOs at the long term feerate.
bool GetAlgoCompleted() const
Get m_algo_completed.
bool m_algo_completed
False if algorithm was cut short by hitting limit of attempts and solution is non-optimal.
bool operator<(const COutput &rhs) const
static constexpr CAmount CHANGE_UPPER
upper bound for randomly-chosen target change amount
Definition: coinselection.h:25
const uint64_t max_cluster_count
Maximum cluster count that a single UTXO in the OutputGroup may have.
void SetAlgoCompleted(bool algo_completed)
Tracks that algorithm was able to exhaustively search the entire combination space before hitting lim...
bool m_from_me
Whether the UTXOs were sent by the wallet to itself.
std::optional< CAmount > effective_value
The output&#39;s value minus fees required to spend it and bump its unconfirmed ancestors to the target f...
Definition: coinselection.h:31
A UTXO under consideration for use in funding a new transaction.
Definition: coinselection.h:28
std::vector< std::shared_ptr< COutput > > GetShuffledInputVector() const
Get the vector of COutputs that will be used to fill in a CTransaction&#39;s vin.
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...
const int conf_theirs
Minimum number of confirmations for outputs received from a different wallet.
size_t m_max_cluster_count
The maximum cluster count of a single UTXO in this output group.
CAmount ancestor_bump_fees
The fee necessary to bump this UTXO&#39;s ancestor transactions to the target feerate.
Definition: coinselection.h:73
int change_spend_size
Size of the input to spend a change output in virtual bytes.
CAmount m_change_fee
Cost of creating the change output.
void Merge(const SelectionResult &other)
Combines the.
CAmount m_target
The target the algorithm selected for.
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
std::map< CoinEligibilityFilter, OutputGroupTypeMap > FilteredOutputGroups