Bitcoin Core  29.1.0
P2P Digital Currency
coin_selection.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2022 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 #include <bench/bench.h>
6 #include <consensus/amount.h>
7 #include <interfaces/chain.h>
8 #include <node/context.h>
9 #include <outputtype.h>
10 #include <policy/feerate.h>
11 #include <policy/policy.h>
12 #include <primitives/transaction.h>
13 #include <random.h>
14 #include <sync.h>
15 #include <util/result.h>
16 #include <wallet/coinselection.h>
17 #include <wallet/spend.h>
18 #include <wallet/test/util.h>
19 #include <wallet/transaction.h>
20 #include <wallet/wallet.h>
21 
22 #include <cassert>
23 #include <map>
24 #include <memory>
25 #include <set>
26 #include <utility>
27 #include <vector>
28 
29 using node::NodeContext;
32 using wallet::COutput;
33 using wallet::CWallet;
34 using wallet::CWalletTx;
41 
42 static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<std::unique_ptr<CWalletTx>>& wtxs)
43 {
44  static int nextLockTime = 0;
46  tx.nLockTime = nextLockTime++; // so all transactions get different hashes
47  tx.vout.resize(1);
48  tx.vout[0].nValue = nValue;
49  wtxs.push_back(std::make_unique<CWalletTx>(MakeTransactionRef(std::move(tx)), TxStateInactive{}));
50 }
51 
52 // Simple benchmark for wallet coin selection. Note that it maybe be necessary
53 // to build up more complicated scenarios in order to get meaningful
54 // measurements of performance. From laanwj, "Wallet coin selection is probably
55 // the hardest, as you need a wider selection of scenarios, just testing the
56 // same one over and over isn't too useful. Generating random isn't useful
57 // either for measurements."
58 // (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
59 static void CoinSelection(benchmark::Bench& bench)
60 {
62  auto chain = interfaces::MakeChain(node);
63  CWallet wallet(chain.get(), "", CreateMockableWalletDatabase());
64  std::vector<std::unique_ptr<CWalletTx>> wtxs;
65  LOCK(wallet.cs_wallet);
66 
67  // Add coins.
68  for (int i = 0; i < 1000; ++i) {
69  addCoin(1000 * COIN, wallet, wtxs);
70  }
71  addCoin(3 * COIN, wallet, wtxs);
72 
73  // Create coins
74  wallet::CoinsResult available_coins;
75  for (const auto& wtx : wtxs) {
76  const auto txout = wtx->tx->vout.at(0);
77  available_coins.coins[OutputType::BECH32].emplace_back(COutPoint(wtx->GetHash(), 0), txout, /*depth=*/6 * 24, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/true, /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true, /*fees=*/ 0);
78  }
79 
81  FastRandomContext rand{};
82  const CoinSelectionParams coin_selection_params{
83  rand,
84  /*change_output_size=*/ 34,
85  /*change_spend_size=*/ 148,
86  /*min_change_target=*/ CHANGE_LOWER,
87  /*effective_feerate=*/ CFeeRate(20'000),
88  /*long_term_feerate=*/ CFeeRate(10'000),
89  /*discard_feerate=*/ CFeeRate(3000),
90  /*tx_noinputs_size=*/ 0,
91  /*avoid_partial=*/ false,
92  };
93  auto group = wallet::GroupOutputs(wallet, available_coins, coin_selection_params, {{filter_standard}})[filter_standard];
94  bench.run([&] {
95  auto result = AttemptSelection(wallet.chain(), 1002.99 * COIN, group, coin_selection_params, /*allow_mixed_output_types=*/true);
96  assert(result);
97  assert(result->GetSelectedValue() == 1003 * COIN);
98  assert(result->GetInputSet().size() == 2);
99  });
100 }
101 
102 // Copied from src/wallet/test/coinselector_tests.cpp
103 static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>& set)
104 {
106  tx.vout.resize(nInput + 1);
107  tx.vout[nInput].nValue = nValue;
108  COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 0, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ true, /*fees=*/ 0);
109  set.emplace_back();
110  set.back().Insert(std::make_shared<COutput>(output), /*ancestors=*/ 0, /*descendants=*/ 0);
111 }
112 // Copied from src/wallet/test/coinselector_tests.cpp
113 static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool)
114 {
115  utxo_pool.clear();
116  CAmount target = 0;
117  for (int i = 0; i < utxos; ++i) {
118  target += CAmount{1} << (utxos+i);
119  add_coin(CAmount{1} << (utxos+i), 2*i, utxo_pool);
120  add_coin((CAmount{1} << (utxos+i)) + (CAmount{1} << (utxos-1-i)), 2*i + 1, utxo_pool);
121  }
122  return target;
123 }
124 
125 static void BnBExhaustion(benchmark::Bench& bench)
126 {
127  // Setup
128  std::vector<OutputGroup> utxo_pool;
129 
130  bench.run([&] {
131  // Benchmark
132  CAmount target = make_hard_case(17, utxo_pool);
133  SelectCoinsBnB(utxo_pool, target, 0, MAX_STANDARD_TX_WEIGHT); // Should exhaust
134 
135  // Cleanup
136  utxo_pool.clear();
137  });
138 }
139 
assert(!tx.IsCoinBase())
static constexpr CAmount CHANGE_LOWER
lower bound for randomly-chosen target change amount
Definition: coinselection.h:23
State of transaction not confirmed or conflicting with a known block and not in the mempool...
Definition: transaction.h:58
static int nextLockTime
std::map< OutputType, std::vector< COutput > > coins
Definition: spend.h:41
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
COutputs available for spending, stored by OutputType.
Definition: spend.h:40
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:176
NodeContext struct containing references to chain state and connection state.
Definition: context.h:56
Bench & run(char const *benchmarkName, Op &&op)
Repeatedly calls op() based on the configuration, and performs measurements.
Definition: nanobench.h:1234
#define LOCK(cs)
Definition: sync.h:257
int CalculateMaximumSignedInputSize(const CTxOut &txout, const COutPoint outpoint, const SigningProvider *provider, bool can_grind_r, const CCoinControl *coin_control)
Definition: spend.cpp:90
Fast randomness source.
Definition: random.h:376
static CAmount make_hard_case(int utxos, std::vector< OutputGroup > &utxo_pool)
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:299
A group of UTXOs paid to the same output script.
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
std::vector< CTxOut > vout
Definition: transaction.h:380
static void add_coin(const CAmount &nValue, int nInput, std::vector< OutputGroup > &set)
Parameters for one iteration of Coin Selection.
util::Result< SelectionResult > SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, const CAmount &cost_of_change, int max_selection_weight)
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:424
util::Result< SelectionResult > AttemptSelection(interfaces::Chain &chain, const CAmount &nTargetValue, OutputGroupTypeMap &groups, const CoinSelectionParams &coin_selection_params, bool allow_mixed_output_types)
Attempt to find a valid input set that preserves privacy by not mixing OutputTypes.
Definition: spend.cpp:663
Definition: messages.h:20
static void addCoin(const CAmount &nValue, const CWallet &wallet, std::vector< std::unique_ptr< CWalletTx >> &wtxs)
Parameters for filtering which OutputGroups we may use in coin selection.
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we&#39;re willing to relay/mine.
Definition: policy.h:34
static const CoinEligibilityFilter filter_standard(1, 6, 0)
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition: util.cpp:186
std::unique_ptr< Chain > MakeChain(node::NodeContext &node)
Return implementation of Chain interface.
auto result
Definition: common-types.h:74
static void CoinSelection(benchmark::Bench &bench)
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
Definition: feerate.h:32
A mutable version of CTransaction.
Definition: transaction.h:377
Main entry point to nanobench&#39;s benchmarking facility.
Definition: nanobench.h:627
static void BnBExhaustion(benchmark::Bench &bench)
A UTXO under consideration for use in funding a new transaction.
Definition: coinselection.h:28
FilteredOutputGroups GroupOutputs(const CWallet &wallet, const CoinsResult &coins, const CoinSelectionParams &coin_sel_params, const std::vector< SelectionFilter > &filters, std::vector< OutputGroup > &ret_discarded_groups)
Definition: spend.cpp:533
BENCHMARK(CoinSelection, benchmark::PriorityLevel::HIGH)
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition: amount.h:15