Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
coinselector_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2017 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 <chainparams.h> // For Params
6#include <consensus/amount.h>
7#include <node/context.h>
9#include <random.h>
10#include <wallet/coincontrol.h>
12#include <wallet/spend.h>
13#include <wallet/wallet.h>
14
15#include <test/util/setup_common.h>
17
18#include <boost/test/unit_test.hpp>
19
20#include <memory>
21#include <random>
22
24
25// how many times to run all the tests to have a chance to catch errors that
26// only show up with particular random shuffles
27#define RUN_TESTS 100
28
29// some tests fail 1% of the time due to bad luck.
30// we repeat those tests this many times and only complain if all iterations of
31// the test fail
32#define RANDOM_REPEATS 5
33
34typedef std::set<CInputCoin> CoinSet;
35
36static std::vector<COutput> vCoins;
39
44 0, false);
45
46static void add_coin(const Amount nValue, int nInput,
47 std::vector<CInputCoin> &set) {
49 tx.vout.resize(nInput + 1);
50 tx.vout[nInput].nValue = nValue;
51 set.emplace_back(MakeTransactionRef(tx), nInput);
52}
53
54static void add_coin(const Amount nValue, int nInput, CoinSet &set) {
56 tx.vout.resize(nInput + 1);
57 tx.vout[nInput].nValue = nValue;
58 set.emplace(MakeTransactionRef(tx), nInput);
59}
60
61static void add_coin(CWallet &wallet, const Amount nValue, int nAge = 6 * 24,
62 bool fIsFromMe = false, int nInput = 0,
63 bool spendable = false) {
64 balance += nValue;
65 static int nextLockTime = 0;
67 // so all transactions get different hashes
69 tx.vout.resize(nInput + 1);
70 tx.vout[nInput].nValue = nValue;
71 if (spendable) {
72 CTxDestination dest;
73 std::string error;
74 assert(wallet.GetNewDestination(OutputType::LEGACY, "", dest, error));
75 tx.vout[nInput].scriptPubKey = GetScriptForDestination(dest);
76 }
77 if (fIsFromMe) {
78 // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if
79 // vin.empty(), so stop vin being empty, and cache a non-zero Debit to
80 // fake out IsFromMe()
81 tx.vin.resize(1);
82 }
83 CWalletTx *wtx = wallet.AddToWallet(MakeTransactionRef(std::move(tx)),
84 /* confirm= */ {});
85 if (fIsFromMe) {
87 wtx->m_is_cache_empty = false;
88 }
89 COutput output(wallet, *wtx, nInput, nAge, true /* spendable */,
90 true /* solvable */, true /* safe */);
91 vCoins.push_back(output);
92}
93
94static void empty_wallet() {
95 vCoins.clear();
97}
98
99static bool equal_sets(CoinSet a, CoinSet b) {
100 std::pair<CoinSet::iterator, CoinSet::iterator> ret =
101 mismatch(a.begin(), a.end(), b.begin());
102 return ret.first == a.end() && ret.second == b.end();
103}
104
105static Amount make_hard_case(int utxos, std::vector<CInputCoin> &utxo_pool) {
106 utxo_pool.clear();
108 for (int i = 0; i < utxos; ++i) {
109 const Amount base = (int64_t(1) << (utxos + i)) * SATOSHI;
110 target += base;
111 add_coin(base, 2 * i, utxo_pool);
112 add_coin(base + (int64_t(1) << (utxos - 1 - i)) * SATOSHI, 2 * i + 1,
113 utxo_pool);
114 }
115 return target;
116}
117
118inline std::vector<OutputGroup> &
119GroupCoins(const std::vector<CInputCoin> &coins) {
120 static std::vector<OutputGroup> static_groups;
121 static_groups.clear();
122 for (auto &coin : coins) {
123 static_groups.emplace_back();
124 static_groups.back().Insert(coin, 0, true, false);
125 }
126 return static_groups;
127}
128
129inline std::vector<OutputGroup> &GroupCoins(const std::vector<COutput> &coins) {
130 static std::vector<OutputGroup> static_groups;
131 static_groups.clear();
132 for (auto &coin : coins) {
133 // HACK: we can't figure out the is_me flag so we use the conditions
134 // defined below; perhaps set safe to false for !fIsFromMe in add_coin()
135 const bool is_me =
136 coin.tx->m_amounts[CWalletTx::DEBIT].m_cached[ISMINE_SPENDABLE] &&
137 coin.tx->m_amounts[CWalletTx::DEBIT].m_value[ISMINE_SPENDABLE] ==
138 SATOSHI;
139 static_groups.emplace_back();
140 static_groups.back().Insert(coin.GetInputCoin(), coin.nDepth, is_me,
141 false);
142 }
143 return static_groups;
144}
145
146// Branch and bound coin selection tests
148 LOCK(m_wallet.cs_wallet);
149 m_wallet.SetupLegacyScriptPubKeyMan();
150
151 // Setup
152 std::vector<CInputCoin> utxo_pool;
157
159 // Known Outcome tests //
161
162 // Empty utxo pool
165 selection.clear();
166
167 // Add utxos
168 add_coin(1 * CENT, 1, utxo_pool);
169 add_coin(2 * CENT, 2, utxo_pool);
170 add_coin(3 * CENT, 3, utxo_pool);
171 add_coin(4 * CENT, 4, utxo_pool);
172
173 // Select 1 Cent
179 actual_selection.clear();
180 selection.clear();
181
182 // Select 2 Cent
188 actual_selection.clear();
189 selection.clear();
190
191 // Select 5 Cent
198 actual_selection.clear();
199 selection.clear();
200
201 // Select 11 Cent, not possible
204 actual_selection.clear();
205 selection.clear();
206
207 // Cost of change is greater than the difference between target value and
208 // utxo sum
211 5 * CENT / 10, selection, value_ret,
215 actual_selection.clear();
216 selection.clear();
217
218 // Cost of change is less than the difference between target value and utxo
219 // sum
223 actual_selection.clear();
224 selection.clear();
225
226 // Select 10 Cent
227 add_coin(5 * CENT, 5, utxo_pool);
235 actual_selection.clear();
236 selection.clear();
237
238 // Negative effective value
239 // Select 10 Cent but have 1 Cent not be possible because too small
246 // FIXME: this test is redundant with the above, because 1 Cent is selected,
247 // not "too small" BOOST_CHECK(equal_sets(selection, actual_selection));
248
249 // Select 0.25 Cent, not possible
252 actual_selection.clear();
253 selection.clear();
254
255 // Iteration exhaustion test
257 // Should exhaust
261 // Should not exhaust
264
265 // Test same value early bailout optimization
266 utxo_pool.clear();
272 add_coin(7 * CENT, 7, utxo_pool);
273 add_coin(7 * CENT, 7, utxo_pool);
274 add_coin(7 * CENT, 7, utxo_pool);
275 add_coin(7 * CENT, 7, utxo_pool);
276 add_coin(2 * CENT, 7, utxo_pool);
277 for (int i = 0; i < 50000; ++i) {
278 add_coin(5 * CENT, 7, utxo_pool);
279 }
284
286 // Behavior tests //
288 // Select 1 Cent with pool of only greater than 5 Cent
289 utxo_pool.clear();
290 for (int i = 5; i <= 20; ++i) {
291 add_coin(i * CENT, i, utxo_pool);
292 }
293 // Run 100 times, to make sure it is never finding a solution
294 for (int i = 0; i < 100; ++i) {
297 }
298
299 // Make sure that effective value is working in SelectCoinsMinConf when BnB
300 // is used
302 true, 0, 0, CFeeRate(3000 * SATOSHI), 0, false);
305 bool bnb_used;
306 empty_wallet();
308 // Make sure that it has a negative effective value. The next check should
309 // assert if this somehow got through. Otherwise it will fail
310 vCoins.at(0).nInputBytes = 40;
314
315 // Test fees subtracted from output:
316 empty_wallet();
317 add_coin(m_wallet, 1 * CENT);
318 vCoins.at(0).nInputBytes = 40;
322 coin_selection_params_bnb.m_subtract_fee_outputs = true;
327
328 // Make sure that can use BnB when there are preset inputs
329 empty_wallet();
330 {
331 auto wallet = std::make_unique<CWallet>(m_node.chain.get(), "",
333 bool firstRun;
334 wallet->LoadWallet(firstRun);
335 LOCK(wallet->cs_wallet);
336 wallet->SetupLegacyScriptPubKeyMan();
337 add_coin(*wallet, 5 * CENT, 6 * 24, false, 0, true);
338 add_coin(*wallet, 3 * CENT, 6 * 24, false, 0, true);
339 add_coin(*wallet, 2 * CENT, 6 * 24, false, 0, true);
342 coin_control.Select(
343 COutPoint(vCoins.at(0).tx->GetId(), vCoins.at(0).i));
350 }
351}
352
356
359 bool bnb_used;
360
361 LOCK(testWallet.cs_wallet);
362 testWallet.SetupLegacyScriptPubKeyMan();
363
364 // test multiple times to allow for differences in the shuffle order
365 for (int i = 0; i < RUN_TESTS; i++) {
366 empty_wallet();
367
368 // with an empty wallet we can't even pay one cent
372
373 // add a new 1 cent coin
374 add_coin(testWallet, 1 * CENT, 4);
375
376 // with a new 1 cent coin, we still can't find a mature 1 cent
380
381 // but we can find a new 1 cent
386 // add a mature 2 cent coin
388
389 // we can't make 3 cents of mature coins
393
394 // we can make 3 cents of new coins
399
400 // add a mature 5 cent coin,
402 // a new 10 cent coin sent from one of our own addresses
403 add_coin(testWallet, 10 * CENT, 3, true);
404 // and a mature 20 cent coin
405 add_coin(testWallet, 20 * CENT);
406
407 // now we have new: 1+10=11 (of which 10 was self-sent), and mature:
408 // 2+5+20=27. total = 38
409
410 // we can't make 38 cents only if we disallow new coins:
414 // we can't even make 37 cents if we don't allow new coins even if
415 // they're from us
419 // but we can make 37 cents if we accept new coins from ourself
424 // and we can make 38 cents if we accept all new coins
429
430 // try making 34 cents from 1,2,5,10,20 - we can't do it exactly
434 // but 35 cents is closest
436 // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got
437 // included (but possible)
438 BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
439
440 // when we try making 7 cents, the smaller coins (1,2,5) are enough. We
441 // should see just 2+5
446 BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
447
448 // when we try making 8 cents, the smaller coins (1,2,5) are exactly
449 // enough.
453 BOOST_CHECK(nValueRet == 8 * CENT);
454 BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
455
456 // when we try making 9 cents, no subset of smaller coins is enough, and
457 // we get the next bigger coin (10)
462 BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
463
464 // now clear out the wallet and start again to test choosing between
465 // subsets of smaller coins and the next biggest coin
466 empty_wallet();
467
471 add_coin(testWallet, 20 * CENT);
472 // now we have 6+7+8+20+30 = 71 cents total
473 add_coin(testWallet, 30 * CENT);
474
475 // check that we have 71 and not 72
482
483 // now try making 16 cents. the best smaller coins can do is 6+7+8 =
484 // 21; not as good at the next biggest coin, 20
488 // we should get 20 in one coin
490 BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
491
492 // now we have 5+6+7+8+20+30 = 75 cents total
494
495 // now if we try making 16 cents again, the smaller coins can make 5+6+7
496 // = 18 cents, better than the next biggest coin, 20
500 // we should get 18 in 3 coins
502 BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
503
504 // now we have 5+6+7+8+18+20+30
505 add_coin(testWallet, 18 * CENT);
506
507 // and now if we try making 16 cents again, the smaller coins can make
508 // 5+6+7 = 18 cents, the same as the next biggest coin, 18
512 // we should get 18 in 1 coin
514 // because in the event of a tie, the biggest coin wins
515 BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
516
517 // now try making 11 cents. we should get 5+6
522 BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
523
524 // check that the smallest bigger coin is used
528 // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
533 // we should get 1,000,000 XEC in 1 coin
535 BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
536
540 // we should get 2,000,000 XEC in 1 coin
542 BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
543
544 // empty the wallet and start again, now with fractions of a cent, to
545 // test small change avoidance
546
547 empty_wallet();
548 add_coin(testWallet, 1 * MIN_CHANGE / 10);
549 add_coin(testWallet, 2 * MIN_CHANGE / 10);
550 add_coin(testWallet, 3 * MIN_CHANGE / 10);
551 add_coin(testWallet, 4 * MIN_CHANGE / 10);
552 add_coin(testWallet, 5 * MIN_CHANGE / 10);
553
554 // try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
555 // we'll get change smaller than MIN_CHANGE whatever happens, so can
556 // expect MIN_CHANGE exactly
561
562 // but if we add a bigger coin, small change is avoided
564
565 // try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
569 // we should get the exact amount
571
572 // if we add more small coins:
573 add_coin(testWallet, 6 * MIN_CHANGE / 10);
574 add_coin(testWallet, 7 * MIN_CHANGE / 10);
575
576 // and try again to make 1.0 * MIN_CHANGE
580 // we should get the exact amount
582
583 // run the 'mtgox' test (see
584 // http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
585 // they tried to consolidate 10 50k coins into one 500k coin, and ended
586 // up with 50k in change
587 empty_wallet();
588 for (int j = 0; j < 20; j++) {
589 add_coin(testWallet, 50000 * COIN);
590 }
591
595 // we should get the exact amount
597 // in ten coins
598 BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U);
599
600 // if there's not enough in the smaller coins to make at least 1 *
601 // MIN_CHANGE change (0.5+0.6+0.7 < 1.0+1.0), we need to try finding an
602 // exact subset anyway
603
604 // sometimes it will fail, and so we use the next biggest coin:
605 empty_wallet();
606 add_coin(testWallet, 5 * MIN_CHANGE / 10);
607 add_coin(testWallet, 6 * MIN_CHANGE / 10);
608 add_coin(testWallet, 7 * MIN_CHANGE / 10);
613 // we get the bigger coin
615 BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
616
617 // but sometimes it's possible, and we use an exact subset (0.4 + 0.6 =
618 // 1.0)
619 empty_wallet();
620 add_coin(testWallet, 4 * MIN_CHANGE / 10);
621 add_coin(testWallet, 6 * MIN_CHANGE / 10);
622 add_coin(testWallet, 8 * MIN_CHANGE / 10);
627 // we should get the exact amount
629 // in two coins 0.4+0.6
630 BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
631
632 // test avoiding small change
633 empty_wallet();
634 add_coin(testWallet, 5 * MIN_CHANGE / 100);
637
638 // trying to make 100.01 from these three coins
642 // we should get all coins
643 BOOST_CHECK_EQUAL(nValueRet, 10105 * MIN_CHANGE / 100);
644 BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
645
646 // but if we try to make 99.9, we should take the bigger of the two
647 // small coins to avoid small change
652 BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
653 }
654
655 // test with many inputs
656 for (Amount amt = 1500 * SATOSHI; amt < COIN; amt = 10 * amt) {
657 empty_wallet();
658 // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148
659 // bytes per input)
660 for (uint16_t j = 0; j < 676; j++) {
662 }
663
664 // We only create the wallet once to save time, but we still run the
665 // coin selection RUN_TESTS times.
666 for (int i = 0; i < RUN_TESTS; i++) {
670
671 if (amt - 2000 * SATOSHI < MIN_CHANGE) {
672 // needs more than one input:
673 uint16_t returnSize = std::ceil(
674 (2000.0 + (MIN_CHANGE / SATOSHI)) / (amt / SATOSHI));
675 Amount returnValue = returnSize * amt;
676 BOOST_CHECK_EQUAL(nValueRet, returnValue);
678 } else {
679 // one input is sufficient:
681 BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
682 }
683 }
684 }
685
686 // test randomness
687 {
688 empty_wallet();
689 for (int i2 = 0; i2 < 100; i2++) {
691 }
692
693 // Again, we only create the wallet once to save time, but we still run
694 // the coin selection RUN_TESTS times.
695 for (int i = 0; i < RUN_TESTS; i++) {
696 // picking 50 from 100 coins doesn't depend on the shuffle, but does
697 // depend on randomness in the stochastic approximation code
705
706 int fails = 0;
707 for (int j = 0; j < RANDOM_REPEATS; j++) {
708 // selecting 1 from 100 identical coins depends on the shuffle;
709 // this test will fail 1% of the time run the test
710 // RANDOM_REPEATS times and only complain if all of them fail
718 fails++;
719 }
720 }
722 }
723
724 // add 75 cents in small change. not enough to make 90 cents, then
725 // try making 90 cents. there are multiple competing "smallest
726 // bigger" coins, one of which should be picked at random
728 add_coin(testWallet, 10 * CENT);
729 add_coin(testWallet, 15 * CENT);
730 add_coin(testWallet, 20 * CENT);
731 add_coin(testWallet, 25 * CENT);
732
733 for (int i = 0; i < RUN_TESTS; i++) {
734 int fails = 0;
735 for (int j = 0; j < RANDOM_REPEATS; j++) {
736 // selecting 1 from 100 identical coins depends on the shuffle;
737 // this test will fail 1% of the time run the test
738 // RANDOM_REPEATS times and only complain if all of them fail
746 fails++;
747 }
748 }
750 }
751 }
752
753 empty_wallet();
754}
755
759 bool bnb_used;
760
761 LOCK(m_wallet.cs_wallet);
762 m_wallet.SetupLegacyScriptPubKeyMan();
763
764 empty_wallet();
765
766 // Test vValue sort order
767 for (int i = 0; i < 1000; i++) {
768 add_coin(m_wallet, 1000 * COIN);
769 }
770 add_coin(m_wallet, 3 * COIN);
771
776 BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
777
778 empty_wallet();
779}
780
781// Tests that with the ideal conditions, the coin selector will always be able
782// to find a solution that can pay the target value
786 testWallet.SetupLegacyScriptPubKeyMan();
787
788 // Random generator stuff
789 std::default_random_engine generator;
790 std::exponential_distribution<double> distribution(100);
792
793 // Run this test 100 times
794 for (int i = 0; i < 100; ++i) {
795 empty_wallet();
796
797 // Make a wallet with 1000 exponentially distributed random inputs
798 for (int j = 0; j < 1000; ++j) {
800 int64_t(10000000 * distribution(generator)) * SATOSHI);
801 }
802
803 // Generate a random fee rate in the range of 100 - 400
804 CFeeRate rate(int64_t(rand.randrange(300) + 100) * SATOSHI);
805
806 // Generate a random target value between 1000 and wallet balance
807 Amount target =
808 int64_t(rand.randrange(balance / SATOSHI - 1000) + 1000) * SATOSHI;
809
810 // Perform selection
812 false, 34, 148, CFeeRate(Amount::zero()), 0, false);
814 true, 34, 148, CFeeRate(Amount::zero()), 0, false);
817 bool bnb_used = false;
825 }
826}
827
static constexpr Amount SATOSHI
Definition amount.h:143
static constexpr Amount COIN
Definition amount.h:144
const CChainParams & Params()
Return the currently selected parameters.
Coin Control Features.
Definition coincontrol.h:21
bool fAllowOtherInputs
If false, allows unselected inputs, but requires all selected inputs be used.
Definition coincontrol.h:32
Fee rate in satoshis per kilobyte: Amount / kB.
Definition feerate.h:21
A mutable version of CTransaction.
std::vector< CTxOut > vout
std::vector< CTxIn > vin
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition transaction.h:20
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition wallet.h:254
A transaction with a bunch of additional info that only the owner cares about.
Definition transaction.h:65
CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
Fast randomness source.
Definition random.h:156
std::set< CInputCoin > CoinSet
static void ApproximateBestSubset(const std::vector< OutputGroup > &groups, const Amount &nTotalLower, const Amount &nTargetValue, std::vector< char > &vfBest, Amount &nBest, int iterations=1000)
bool SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const Amount &target_value, const Amount &cost_of_change, std::set< CInputCoin > &out_set, Amount &value_ret, const Amount not_input_fees)
This is the Branch and Bound Coin Selection algorithm designed by Murch.
static constexpr Amount MIN_CHANGE
target minimum change amount
CoinEligibilityFilter filter_standard_extra(6, 6)
static std::vector< COutput > vCoins
static void empty_wallet()
static node::NodeContext testNode
BOOST_AUTO_TEST_CASE(bnb_search_test)
CoinSelectionParams coin_selection_params(false, 0, 0, CFeeRate(Amount::zero()), 0, false)
static bool equal_sets(CoinSet a, CoinSet b)
std::set< CInputCoin > CoinSet
std::vector< OutputGroup > & GroupCoins(const std::vector< CInputCoin > &coins)
CoinEligibilityFilter filter_standard(1, 6)
CoinEligibilityFilter filter_confirmed(1, 1)
#define RANDOM_REPEATS
static Amount make_hard_case(int utxos, std::vector< CInputCoin > &utxo_pool)
static Amount balance
#define RUN_TESTS
static void add_coin(const Amount nValue, int nInput, std::vector< CInputCoin > &set)
@ ISMINE_SPENDABLE
Definition ismine.h:21
bool error(const char *fmt, const Args &...args)
Definition logging.h:226
std::unique_ptr< Chain > MakeChain(node::NodeContext &node, const CChainParams &params)
Return implementation of Chain interface.
NodeContext & m_node
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:18
#define BOOST_CHECK(expr)
Definition object.cpp:17
static CTransactionRef MakeTransactionRef()
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
bool SelectCoinsMinConf(const CWallet &wallet, const Amount nTargetValue, const CoinEligibilityFilter &eligibility_filter, std::vector< COutput > coins, std::set< CInputCoin > &setCoinsRet, Amount &nValueRet, const CoinSelectionParams &coin_selection_params, bool &bnb_used)
Shuffle and select coins until nTargetValue is reached while avoiding small change; This method is st...
Definition spend.cpp:422
bool SelectCoins(const CWallet &wallet, const std::vector< COutput > &vAvailableCoins, const Amount nTargetValue, std::set< CInputCoin > &setCoinsRet, Amount &nValueRet, const CCoinControl &coin_control, CoinSelectionParams &coin_selection_params, bool &bnb_used)
Select a set of coins such that nValueRet >= nTargetValue and at least all coins from coin_control ar...
Definition spend.cpp:474
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition standard.cpp:240
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition standard.h:85
static constexpr Amount zero() noexcept
Definition amount.h:32
void Set(isminefilter filter, Amount value)
Definition ismine.h:39
Testing setup and teardown for wallet.
NodeContext struct containing references to chain state and connection state.
Definition context.h:43
#define LOCK(cs)
Definition sync.h:306
assert(!tx.IsCoinBase())
std::shared_ptr< CWallet > m_wallet
std::unique_ptr< WalletDatabase > CreateDummyWalletDatabase()
Return object for accessing dummy database with no read/write capabilities.
std::unique_ptr< WalletDatabase > CreateMockWalletDatabase()
Return object for accessing temporary in-memory database.