Bitcoin Core  31.0.0
P2P Digital Currency
txdownload_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-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 #include <addresstype.h>
6 #include <consensus/validation.h>
7 #include <net_processing.h>
10 #include <script/script.h>
11 #include <test/util/common.h>
12 #include <test/util/random.h>
13 #include <test/util/setup_common.h>
14 #include <validation.h>
15 
16 #include <array>
17 
18 #include <boost/test/unit_test.hpp>
19 
20 BOOST_FIXTURE_TEST_SUITE(txdownload_tests, TestingSetup)
21 
22 struct Behaviors {
30 
31  // Constructor. We are passing and casting ints because they are more readable in a table (see expected_behaviors).
32  Behaviors(bool txid_rejects, bool wtxid_rejects, bool txid_recon, bool wtxid_recon, bool keep, bool txid_inv, bool wtxid_inv) :
33  m_txid_in_rejects(txid_rejects),
34  m_wtxid_in_rejects(wtxid_rejects),
35  m_txid_in_rejects_recon(txid_recon),
36  m_wtxid_in_rejects_recon(wtxid_recon),
37  m_keep_for_compact(keep),
38  m_ignore_inv_txid(txid_inv),
39  m_ignore_inv_wtxid(wtxid_inv)
40  {}
41 
42  void CheckEqual(const Behaviors& other, bool segwit)
43  {
44  BOOST_CHECK_EQUAL(other.m_wtxid_in_rejects, m_wtxid_in_rejects);
45  BOOST_CHECK_EQUAL(other.m_wtxid_in_rejects_recon, m_wtxid_in_rejects_recon);
46  BOOST_CHECK_EQUAL(other.m_keep_for_compact, m_keep_for_compact);
47  BOOST_CHECK_EQUAL(other.m_ignore_inv_wtxid, m_ignore_inv_wtxid);
48 
49  // false negatives for nonsegwit transactions, since txid == wtxid.
50  if (segwit) {
51  BOOST_CHECK_EQUAL(other.m_txid_in_rejects, m_txid_in_rejects);
52  BOOST_CHECK_EQUAL(other.m_txid_in_rejects_recon, m_txid_in_rejects_recon);
53  BOOST_CHECK_EQUAL(other.m_ignore_inv_txid, m_ignore_inv_txid);
54  }
55  }
56 };
57 
58 // Map from failure reason to expected behavior for a segwit tx that fails
59 // Txid and Wtxid are assumed to be different here. For a nonsegwit transaction, use the wtxid results.
60 static std::map<TxValidationResult, Behaviors> expected_behaviors{
61  {TxValidationResult::TX_CONSENSUS, {/*txid_rejects*/0,/*wtxid_rejects*/1,/*txid_recon*/0,/*wtxid_recon*/0,/*keep*/1,/*txid_inv*/0,/*wtxid_inv*/1}},
62  {TxValidationResult::TX_INPUTS_NOT_STANDARD, { 1, 1, 0, 0, 1, 1, 1}},
63  {TxValidationResult::TX_NOT_STANDARD, { 0, 1, 0, 0, 1, 0, 1}},
64  {TxValidationResult::TX_MISSING_INPUTS, { 0, 0, 0, 0, 1, 0, 1}},
65  {TxValidationResult::TX_PREMATURE_SPEND, { 0, 1, 0, 0, 1, 0, 1}},
66  {TxValidationResult::TX_WITNESS_MUTATED, { 0, 1, 0, 0, 1, 0, 1}},
67  {TxValidationResult::TX_WITNESS_STRIPPED, { 0, 0, 0, 0, 0, 0, 0}},
68  {TxValidationResult::TX_CONFLICT, { 0, 1, 0, 0, 1, 0, 1}},
69  {TxValidationResult::TX_MEMPOOL_POLICY, { 0, 1, 0, 0, 1, 0, 1}},
70  {TxValidationResult::TX_NO_MEMPOOL, { 0, 1, 0, 0, 1, 0, 1}},
71  {TxValidationResult::TX_RECONSIDERABLE, { 0, 0, 0, 1, 1, 0, 1}},
72  {TxValidationResult::TX_UNKNOWN, { 0, 1, 0, 0, 1, 0, 1}},
73 };
74 
75 static bool CheckOrphanBehavior(node::TxDownloadManagerImpl& txdownload_impl, const CTransactionRef& tx, const node::RejectedTxTodo& ret, std::string& err_msg,
76  bool expect_orphan, bool expect_keep, unsigned int expected_parents)
77 {
78  // Missing inputs can never result in a PackageToValidate.
79  if (ret.m_package_to_validate.has_value()) {
80  err_msg = strprintf("returned a PackageToValidate on missing inputs");
81  return false;
82  }
83 
84  if (expect_orphan != txdownload_impl.m_orphanage->HaveTx(tx->GetWitnessHash())) {
85  err_msg = strprintf("unexpectedly %s tx in orphanage", expect_orphan ? "did not find" : "found");
86  return false;
87  }
88  if (expect_keep != ret.m_should_add_extra_compact_tx) {
89  err_msg = strprintf("unexpectedly returned %s add to vExtraTxnForCompact", expect_keep ? "should not" : "should");
90  return false;
91  }
92  if (expected_parents != ret.m_unique_parents.size()) {
93  err_msg = strprintf("expected %u unique_parents, got %u", expected_parents, ret.m_unique_parents.size());
94  return false;
95  }
96  return true;
97 }
98 
100 {
101  // Each tx returned from here spends the previous one.
102  static Txid prevout_hash{};
103 
105  mtx.vin.emplace_back(prevout_hash, 0);
106  // This makes txid != wtxid
107  if (segwit) mtx.vin[0].scriptWitness.stack.push_back({1});
108  mtx.vout.emplace_back(CENT, CScript());
109  auto ptx = MakeTransactionRef(mtx);
110  prevout_hash = ptx->GetHash();
111  return ptx;
112 }
113 
115 {
116  CTxMemPool& pool = *Assert(m_node.mempool);
117  FastRandomContext det_rand{true};
118  node::TxDownloadOptions DEFAULT_OPTS{pool, det_rand, true};
119 
120  // A new TxDownloadManagerImpl is created for each tx so we can just reuse the same one.
121  TxValidationState state;
122  NodeId nodeid{0};
123  std::chrono::microseconds now{GetTime()};
124  node::TxDownloadConnectionInfo connection_info{/*m_preferred=*/false, /*m_relay_permissions=*/false, /*m_wtxid_relay=*/true};
125 
126  for (const auto segwit_parent : {true, false}) {
127  for (const auto segwit_child : {true, false}) {
128  const auto ptx_parent = CreatePlaceholderTx(segwit_parent);
129  const auto ptx_child = CreatePlaceholderTx(segwit_child);
130  const auto& parent_txid = ptx_parent->GetHash();
131  const auto& parent_wtxid = ptx_parent->GetWitnessHash();
132  const auto& child_txid = ptx_child->GetHash();
133  const auto& child_wtxid = ptx_child->GetWitnessHash();
134 
135  for (const auto& [result, expected_behavior] : expected_behaviors) {
136  node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS};
137  txdownload_impl.ConnectedPeer(nodeid, connection_info);
138  // Parent failure
139  state.Invalid(result, "");
140  const auto& [keep, unique_txids, package_to_validate] = txdownload_impl.MempoolRejectedTx(ptx_parent, state, nodeid, /*first_time_failure=*/true);
141 
142  // No distinction between txid and wtxid caching for nonsegwit transactions, so only test these specific
143  // behaviors for segwit transactions.
144  Behaviors actual_behavior{
145  /*txid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_txid.ToUint256()),
146  /*wtxid_rejects=*/txdownload_impl.RecentRejectsFilter().contains(parent_wtxid.ToUint256()),
147  /*txid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()),
148  /*wtxid_recon=*/txdownload_impl.RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256()),
149  /*keep=*/keep,
150  /*txid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, parent_txid, now),
151  /*wtxid_inv=*/txdownload_impl.AddTxAnnouncement(nodeid, parent_wtxid, now),
152  };
153  BOOST_TEST_MESSAGE("Testing behavior for " << result << (segwit_parent ? " segwit " : " nonsegwit"));
154  actual_behavior.CheckEqual(expected_behavior, /*segwit=*/segwit_parent);
155 
156  // Later, a child of this transaction fails for missing inputs
158  txdownload_impl.MempoolRejectedTx(ptx_child, state, nodeid, /*first_time_failure=*/true);
159 
160  // If parent (by txid) was rejected, child is too.
161  const bool parent_txid_rejected{segwit_parent ? expected_behavior.m_txid_in_rejects : expected_behavior.m_wtxid_in_rejects};
162  BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_txid.ToUint256()));
163  BOOST_CHECK_EQUAL(parent_txid_rejected, txdownload_impl.RecentRejectsFilter().contains(child_wtxid.ToUint256()));
164 
165  // Unless rejected, the child should be in orphanage.
166  BOOST_CHECK_EQUAL(!parent_txid_rejected, txdownload_impl.m_orphanage->HaveTx(ptx_child->GetWitnessHash()));
167  }
168  }
169  }
170 }
171 
173 {
174  CTxMemPool& pool = *Assert(m_node.mempool);
175  FastRandomContext det_rand{true};
176  node::TxDownloadOptions DEFAULT_OPTS{pool, det_rand, true};
177  NodeId nodeid{1};
178  node::TxDownloadConnectionInfo DEFAULT_CONN{/*m_preferred=*/false, /*m_relay_permissions=*/false, /*m_wtxid_relay=*/true};
179 
180  // We need mature coinbases
181  mineBlocks(20);
182 
183  // Transactions with missing inputs are treated differently depending on how much we know about
184  // their parents.
185  CKey wallet_key = GenerateRandomKey();
186  CScript destination = GetScriptForDestination(PKHash(wallet_key.GetPubKey()));
187  // Amount for spending coinbase in a 1-in-1-out tx, at depth n, each time deducting 1000 from the amount as fees.
188  CAmount amount_depth_1{50 * COIN - 1000};
189  CAmount amount_depth_2{amount_depth_1 - 1000};
190  // Amount for spending coinbase in a 1-in-2-out tx, deducting 1000 in fees
191  CAmount amount_split_half{25 * COIN - 500};
192  int test_chain_height{100};
193 
194  TxValidationState state_orphan;
196 
197  // Transactions are not all submitted to mempool. Conserve the number of m_coinbase_txns we
198  // consume, and only increment this index number when we would conflict with an existing
199  // mempool transaction.
200  size_t coinbase_idx{0};
201 
202  for (int decisions = 0; decisions < (1 << 4); ++decisions) {
203  auto mtx_single_parent = CreateValidMempoolTransaction(m_coinbase_txns[coinbase_idx], /*input_vout=*/0, test_chain_height, coinbaseKey, destination, amount_depth_1, /*submit=*/false);
204  auto single_parent = MakeTransactionRef(mtx_single_parent);
205 
206  auto mtx_orphan = CreateValidMempoolTransaction(single_parent, /*input_vout=*/0, test_chain_height, wallet_key, destination, amount_depth_2, /*submit=*/false);
207  auto orphan = MakeTransactionRef(mtx_orphan);
208 
209  node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS};
210  txdownload_impl.ConnectedPeer(nodeid, DEFAULT_CONN);
211 
212  // Each bit of decisions tells us whether the parent is in a particular cache.
213  // It is definitely possible for a transaction to be in multiple caches. For example, it
214  // may have both a low feerate and found to violate some mempool policy when validated
215  // in a 1p1c.
216  const bool parent_recent_rej(decisions & 1);
217  const bool parent_recent_rej_recon((decisions >> 1) & 1);
218  const bool parent_recent_conf((decisions >> 2) & 1);
219  const bool parent_in_mempool((decisions >> 3) & 1);
220 
221  if (parent_recent_rej) txdownload_impl.RecentRejectsFilter().insert(single_parent->GetHash().ToUint256());
222  if (parent_recent_rej_recon) txdownload_impl.RecentRejectsReconsiderableFilter().insert(single_parent->GetHash().ToUint256());
223  if (parent_recent_conf) txdownload_impl.RecentConfirmedTransactionsFilter().insert(single_parent->GetHash().ToUint256());
224  if (parent_in_mempool) {
225  const auto mempool_result = WITH_LOCK(::cs_main, return m_node.chainman->ProcessTransaction(single_parent));
226  BOOST_CHECK(mempool_result.m_result_type == MempoolAcceptResult::ResultType::VALID);
227  coinbase_idx += 1;
228  assert(coinbase_idx < m_coinbase_txns.size());
229  }
230 
231  // Whether or not the transaction is added as an orphan depends solely on whether or not
232  // it's in RecentRejectsFilter. Specifically, the parent is allowed to be in
233  // RecentRejectsReconsiderableFilter, but it cannot be in RecentRejectsFilter.
234  const bool expect_keep_orphan = !parent_recent_rej;
235  const unsigned int expected_parents = parent_recent_rej || parent_recent_conf || parent_in_mempool ? 0 : 1;
236  // If we don't expect to keep the orphan then expected_parents is 0.
237  // !expect_keep_orphan => (expected_parents == 0)
238  BOOST_CHECK(expect_keep_orphan || expected_parents == 0);
239  const auto ret_1p1c = txdownload_impl.MempoolRejectedTx(orphan, state_orphan, nodeid, /*first_time_failure=*/true);
240  std::string err_msg;
241  const bool ok = CheckOrphanBehavior(txdownload_impl, orphan, ret_1p1c, err_msg,
242  /*expect_orphan=*/expect_keep_orphan, /*expect_keep=*/true, /*expected_parents=*/expected_parents);
243  BOOST_CHECK_MESSAGE(ok, err_msg);
244  }
245 
246  // Orphan with multiple parents
247  {
248  std::vector<CTransactionRef> parents;
249  std::vector<COutPoint> outpoints;
250  int32_t num_parents{24};
251  for (int32_t i = 0; i < num_parents; ++i) {
252  assert(coinbase_idx < m_coinbase_txns.size());
253  auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[coinbase_idx++], /*input_vout=*/0, test_chain_height,
254  coinbaseKey, destination, amount_depth_1 + i, /*submit=*/false);
255  auto ptx_parent = MakeTransactionRef(mtx_parent);
256  parents.emplace_back(ptx_parent);
257  outpoints.emplace_back(ptx_parent->GetHash(), 0);
258  }
259 
260  // Send all coins to 1 output.
261  auto mtx_orphan = CreateValidMempoolTransaction(parents, outpoints, test_chain_height, {wallet_key}, {{amount_depth_2 * num_parents, destination}}, /*submit=*/false);
262  auto orphan = MakeTransactionRef(mtx_orphan);
263 
264  // 1 parent in RecentRejectsReconsiderableFilter, the rest are unknown
265  {
266  node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS};
267  txdownload_impl.ConnectedPeer(nodeid, DEFAULT_CONN);
268 
269  txdownload_impl.RecentRejectsReconsiderableFilter().insert(parents[0]->GetHash().ToUint256());
270  const auto ret_1p1c_parent_reconsiderable = txdownload_impl.MempoolRejectedTx(orphan, state_orphan, nodeid, /*first_time_failure=*/true);
271  std::string err_msg;
272  const bool ok = CheckOrphanBehavior(txdownload_impl, orphan, ret_1p1c_parent_reconsiderable, err_msg,
273  /*expect_orphan=*/true, /*expect_keep=*/true, /*expected_parents=*/num_parents);
274  BOOST_CHECK_MESSAGE(ok, err_msg);
275  }
276 
277  // 1 parent in RecentRejectsReconsiderableFilter, the rest are confirmed
278  {
279  node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS};
280  txdownload_impl.ConnectedPeer(nodeid, DEFAULT_CONN);
281 
282  txdownload_impl.RecentRejectsReconsiderableFilter().insert(parents[0]->GetHash().ToUint256());
283  for (int32_t i = 1; i < num_parents; ++i) {
284  txdownload_impl.RecentConfirmedTransactionsFilter().insert(parents[i]->GetHash().ToUint256());
285  }
286  const unsigned int expected_parents = 1;
287 
288  const auto ret_1recon_conf = txdownload_impl.MempoolRejectedTx(orphan, state_orphan, nodeid, /*first_time_failure=*/true);
289  std::string err_msg;
290  const bool ok = CheckOrphanBehavior(txdownload_impl, orphan, ret_1recon_conf, err_msg,
291  /*expect_orphan=*/true, /*expect_keep=*/true, /*expected_parents=*/expected_parents);
292  BOOST_CHECK_MESSAGE(ok, err_msg);
293  }
294 
295  // 1 parent in RecentRejectsReconsiderableFilter, 1 other in {RecentRejectsReconsiderableFilter, RecentRejectsFilter}
296  for (int i = 0; i < 2; ++i) {
297  node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS};
298  txdownload_impl.ConnectedPeer(nodeid, DEFAULT_CONN);
299 
300  txdownload_impl.RecentRejectsReconsiderableFilter().insert(parents[1]->GetHash().ToUint256());
301 
302  // Doesn't really matter which parent
303  auto& alreadyhave_parent = parents[0];
304  if (i == 0) {
305  txdownload_impl.RecentRejectsReconsiderableFilter().insert(alreadyhave_parent->GetHash().ToUint256());
306  } else if (i == 1) {
307  txdownload_impl.RecentRejectsFilter().insert(alreadyhave_parent->GetHash().ToUint256());
308  }
309 
310  const auto ret_2_problems = txdownload_impl.MempoolRejectedTx(orphan, state_orphan, nodeid, /*first_time_failure=*/true);
311  std::string err_msg;
312  const bool ok = CheckOrphanBehavior(txdownload_impl, orphan, ret_2_problems, err_msg,
313  /*expect_orphan=*/false, /*expect_keep=*/true, /*expected_parents=*/0);
314  BOOST_CHECK_MESSAGE(ok, err_msg);
315  }
316  }
317 
318  // Orphan with multiple inputs spending from a single parent
319  {
320  assert(coinbase_idx < m_coinbase_txns.size());
321  auto parent_2outputs = MakeTransactionRef(CreateValidMempoolTransaction({m_coinbase_txns[coinbase_idx]}, {{m_coinbase_txns[coinbase_idx]->GetHash(), 0}}, test_chain_height, {coinbaseKey},
322  {{amount_split_half, destination}, {amount_split_half, destination}}, /*submit=*/false));
323 
324  auto orphan = MakeTransactionRef(CreateValidMempoolTransaction({parent_2outputs}, {{parent_2outputs->GetHash(), 0}, {parent_2outputs->GetHash(), 1}},
325  test_chain_height, {wallet_key}, {{amount_depth_2, destination}}, /*submit=*/false));
326  // Parent is in RecentRejectsReconsiderableFilter. Inputs will find it twice, but this
327  // should only counts as 1 parent in the filter.
328  {
329  node::TxDownloadManagerImpl txdownload_impl{DEFAULT_OPTS};
330  txdownload_impl.ConnectedPeer(nodeid, DEFAULT_CONN);
331 
332  txdownload_impl.RecentRejectsReconsiderableFilter().insert(parent_2outputs->GetHash().ToUint256());
333  const auto ret_1p1c_2reconsiderable = txdownload_impl.MempoolRejectedTx(orphan, state_orphan, nodeid, /*first_time_failure=*/true);
334  std::string err_msg;
335  const bool ok = CheckOrphanBehavior(txdownload_impl, orphan, ret_1p1c_2reconsiderable, err_msg,
336  /*expect_orphan=*/true, /*expect_keep=*/true, /*expected_parents=*/1);
337  BOOST_CHECK_MESSAGE(ok, err_msg);
338  }
339  }
340 }
341 
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
int ret
invalid by consensus rules
assert(!tx.IsCoinBase())
node::NodeContext m_node
Definition: bitcoin-gui.cpp:43
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:183
transaction was not validated because package failed
std::vector< CTxIn > vin
Definition: transaction.h:359
transaction was missing some of its inputs
int64_t GetTime()
DEPRECATED, see GetTime.
Definition: time.cpp:81
violated mempool&#39;s fee/size/descendant/RBF/etc limits
inputs (covered by txid) failed policy rules
static std::map< TxValidationResult, Behaviors > expected_behaviors
transaction spends a coinbase too early, or violates locktime/sequence locks
bool m_txid_in_rejects
std::unique_ptr< CTxMemPool > mempool
Definition: context.h:68
CKey GenerateRandomKey(bool compressed) noexcept
Definition: key.cpp:475
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
Definition: validation.h:88
static bool CheckOrphanBehavior(node::TxDownloadManagerImpl &txdownload_impl, const CTransactionRef &tx, const node::RejectedTxTodo &ret, std::string &err_msg, bool expect_orphan, bool expect_keep, unsigned int expected_parents)
Transaction might have a witness prior to SegWit activation, or witness may have been malleated (whic...
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
std::unique_ptr< TxOrphanage > m_orphanage
Manages unvalidated tx data (orphan transactions for which we are downloading ancestors).
Behaviors(bool txid_rejects, bool wtxid_rejects, bool txid_recon, bool wtxid_recon, bool keep, bool txid_inv, bool wtxid_inv)
Fast randomness source.
Definition: random.h:385
BOOST_AUTO_TEST_SUITE_END()
static CTransactionRef CreatePlaceholderTx(bool segwit)
int64_t NodeId
Definition: net.h:103
bool m_ignore_inv_wtxid
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition: setup_common.h:146
bool m_ignore_inv_txid
std::vector< CTxOut > vout
Definition: transaction.h:360
void CheckEqual(const Behaviors &other, bool segwit)
fails some policy, but might be acceptable if submitted in a (different) package
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:289
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
Transaction is missing a witness.
BOOST_FIXTURE_TEST_CASE(tx_rejection_types, TestChain100Setup)
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:186
auto result
Definition: common-types.h:74
bool m_wtxid_in_rejects_recon
bool m_keep_for_compact
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:404
bool m_wtxid_in_rejects
this node does not have a mempool so can&#39;t validate the transaction
A mutable version of CTransaction.
Definition: transaction.h:357
static constexpr CAmount CENT
Definition: setup_common.h:47
An encapsulated private key.
Definition: key.h:35
void ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo &info)
bool m_txid_in_rejects_recon
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: cs_main.cpp:8
Tx already in mempool or conflicts with a tx in the chain (if it conflicts with another tx in mempool...
otherwise didn&#39;t meet our local policy rules
std::unique_ptr< ChainstateManager > chainman
Definition: context.h:72
Testing setup that configures a complete environment.
Definition: setup_common.h:121
#define Assert(val)
Identity function.
Definition: check.h:113
#define BOOST_CHECK(expr)
Definition: object.cpp:16
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition: amount.h:15