Bitcoin Core  31.0.0
P2P Digital Currency
validation_chainstatemanager_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-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 <chainparams.h>
6 #include <consensus/validation.h>
10 #include <node/utxo_snapshot.h>
11 #include <random.h>
12 #include <rpc/blockchain.h>
13 #include <sync.h>
14 #include <test/util/chainstate.h>
15 #include <test/util/common.h>
16 #include <test/util/logging.h>
17 #include <test/util/random.h>
18 #include <test/util/setup_common.h>
19 #include <test/util/validation.h>
20 #include <uint256.h>
21 #include <util/result.h>
22 #include <util/vector.h>
23 #include <validation.h>
24 #include <validationinterface.h>
25 
26 #include <tinyformat.h>
27 
28 #include <vector>
29 
30 #include <boost/test/unit_test.hpp>
31 
32 using node::BlockManager;
35 
36 BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, TestingSetup)
37 
42 {
43  ChainstateManager& manager = *m_node.chainman;
44 
46 
47  // Create a legacy (IBD) chainstate.
48  //
49  Chainstate& c1 = manager.ActiveChainstate();
50 
52  {
53  LOCK(manager.GetMutex());
54  BOOST_CHECK_EQUAL(manager.m_chainstates.size(), 1);
55  BOOST_CHECK_EQUAL(manager.m_chainstates[0].get(), &c1);
56  }
57 
58  auto& active_chain = WITH_LOCK(manager.GetMutex(), return manager.ActiveChain());
59  BOOST_CHECK_EQUAL(&active_chain, &c1.m_chain);
60 
61  // Get to a valid assumeutxo tip (per chainparams);
62  mineBlocks(10);
63  BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 110);
64  auto active_tip = WITH_LOCK(manager.GetMutex(), return manager.ActiveTip());
65  auto exp_tip = c1.m_chain.Tip();
66  BOOST_CHECK_EQUAL(active_tip, exp_tip);
67 
69 
70  // Create a snapshot-based chainstate.
71  //
72  const uint256 snapshot_blockhash = active_tip->GetBlockHash();
73  Chainstate& c2{WITH_LOCK(::cs_main, return manager.AddChainstate(std::make_unique<Chainstate>(nullptr, manager.m_blockman, manager, snapshot_blockhash)))};
74  c2.InitCoinsDB(
75  /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
76  {
77  LOCK(::cs_main);
78  c2.InitCoinsCache(1 << 23);
79  c2.CoinsTip().SetBestBlock(active_tip->GetBlockHash());
80  for (const auto& cs : manager.m_chainstates) {
81  cs->ClearBlockIndexCandidates();
82  }
83  c2.LoadChainTip();
84  for (const auto& cs : manager.m_chainstates) {
85  cs->PopulateBlockIndexCandidates();
86  }
87  }
89  BOOST_CHECK(c2.ActivateBestChain(_, nullptr));
90 
91  BOOST_CHECK_EQUAL(WITH_LOCK(::cs_main, return *manager.CurrentChainstate().m_from_snapshot_blockhash), snapshot_blockhash);
92  BOOST_CHECK(WITH_LOCK(::cs_main, return manager.CurrentChainstate().m_assumeutxo == Assumeutxo::UNVALIDATED));
93  BOOST_CHECK_EQUAL(&c2, &manager.ActiveChainstate());
94  BOOST_CHECK(&c1 != &manager.ActiveChainstate());
95  {
96  LOCK(manager.GetMutex());
97  BOOST_CHECK_EQUAL(manager.m_chainstates.size(), 2);
98  BOOST_CHECK_EQUAL(manager.m_chainstates[0].get(), &c1);
99  BOOST_CHECK_EQUAL(manager.m_chainstates[1].get(), &c2);
100  }
101 
102  auto& active_chain2 = WITH_LOCK(manager.GetMutex(), return manager.ActiveChain());
103  BOOST_CHECK_EQUAL(&active_chain2, &c2.m_chain);
104 
105  BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 110);
106  mineBlocks(1);
107  BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 111);
108  BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return c1.m_chain.Height()), 110);
109 
110  auto active_tip2 = WITH_LOCK(manager.GetMutex(), return manager.ActiveTip());
111  BOOST_CHECK_EQUAL(active_tip, active_tip2->pprev);
112  BOOST_CHECK_EQUAL(active_tip, c1.m_chain.Tip());
113  BOOST_CHECK_EQUAL(active_tip2, c2.m_chain.Tip());
114 
115  // Let scheduler events finish running to avoid accessing memory that is going to be unloaded
116  m_node.validation_signals->SyncWithValidationInterfaceQueue();
117 }
118 
120 BOOST_FIXTURE_TEST_CASE(chainstatemanager_rebalance_caches, TestChain100Setup)
121 {
122  ChainstateManager& manager = *m_node.chainman;
123 
124  size_t max_cache = 10000;
125  manager.m_total_coinsdb_cache = max_cache;
126  manager.m_total_coinstip_cache = max_cache;
127 
128  std::vector<Chainstate*> chainstates;
129 
130  // Create a legacy (IBD) chainstate.
131  //
132  Chainstate& c1 = manager.ActiveChainstate();
133  chainstates.push_back(&c1);
134  {
135  LOCK(::cs_main);
136  c1.InitCoinsCache(1 << 23);
137  manager.MaybeRebalanceCaches();
138  }
139 
142 
143  // Create a snapshot-based chainstate.
144  //
145  CBlockIndex* snapshot_base{WITH_LOCK(manager.GetMutex(), return manager.ActiveChain()[manager.ActiveChain().Height() / 2])};
146  Chainstate& c2{WITH_LOCK(::cs_main, return manager.AddChainstate(std::make_unique<Chainstate>(nullptr, manager.m_blockman, manager, *snapshot_base->phashBlock)))};
147  chainstates.push_back(&c2);
148  c2.InitCoinsDB(
149  /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
150 
151  // Reset IBD state so IsInitialBlockDownload() returns true and causes
152  // MaybeRebalanceCaches() to prioritize the snapshot chainstate, giving it
153  // more cache space than the snapshot chainstate. Calling ResetIbd() is
154  // necessary because m_cached_is_ibd is already latched to false before
155  // the test starts due to the test setup. After ResetIbd() is called,
156  // IsInitialBlockDownload() will return true because at this point the active
157  // chainstate has a null chain tip.
158  static_cast<TestChainstateManager&>(manager).ResetIbd();
159 
160  {
161  LOCK(::cs_main);
162  c2.InitCoinsCache(1 << 23);
163  manager.MaybeRebalanceCaches();
164  }
165 
166  BOOST_CHECK_CLOSE(double(c1.m_coinstip_cache_size_bytes), max_cache * 0.05, 1);
167  BOOST_CHECK_CLOSE(double(c1.m_coinsdb_cache_size_bytes), max_cache * 0.05, 1);
168  BOOST_CHECK_CLOSE(double(c2.m_coinstip_cache_size_bytes), max_cache * 0.95, 1);
169  BOOST_CHECK_CLOSE(double(c2.m_coinsdb_cache_size_bytes), max_cache * 0.95, 1);
170 }
171 
172 BOOST_FIXTURE_TEST_CASE(chainstatemanager_ibd_exit_after_loading_blocks, ChainTestingSetup)
173 {
174  CBlockIndex tip;
176  auto apply{[&](bool cached_is_ibd, bool loading_blocks, bool tip_exists, bool enough_work, bool tip_recent) {
177  LOCK(::cs_main);
178  chainman.ResetChainstates();
179  chainman.InitializeChainstate(m_node.mempool.get());
180 
181  const auto recent_time{Now<NodeSeconds>() - chainman.m_options.max_tip_age};
182 
183  chainman.m_cached_is_ibd.store(cached_is_ibd, std::memory_order_relaxed);
184  chainman.m_blockman.m_importing = loading_blocks;
185  if (tip_exists) {
186  tip.nChainWork = chainman.MinimumChainWork() - (enough_work ? 0 : 1);
187  tip.nTime = (recent_time - (tip_recent ? 0h : 100h)).time_since_epoch().count();
188  chainman.ActiveChain().SetTip(tip);
189  } else {
190  assert(!chainman.ActiveChain().Tip());
191  }
192  chainman.UpdateIBDStatus();
193  }};
194 
195  for (const bool cached_is_ibd : {false, true}) {
196  for (const bool loading_blocks : {false, true}) {
197  for (const bool tip_exists : {false, true}) {
198  for (const bool enough_work : {false, true}) {
199  for (const bool tip_recent : {false, true}) {
200  apply(cached_is_ibd, loading_blocks, tip_exists, enough_work, tip_recent);
201  const bool expected_ibd = cached_is_ibd && (loading_blocks || !tip_exists || !enough_work || !tip_recent);
202  BOOST_CHECK_EQUAL(chainman.IsInitialBlockDownload(), expected_ibd);
203  }
204  }
205  }
206  }
207  }
208 }
209 
211  // Run with coinsdb on the filesystem to support, e.g., moving invalidated
212  // chainstate dirs to "*_invalid".
213  //
214  // Note that this means the tests run considerably slower than in-memory DB
215  // tests, but we can't otherwise test this functionality since it relies on
216  // destructive filesystem operations.
218  {},
219  {
220  .coins_db_in_memory = false,
221  .block_tree_db_in_memory = false,
222  },
223  }
224  {
225  }
226 
227  std::tuple<Chainstate*, Chainstate*> SetupSnapshot()
228  {
229  ChainstateManager& chainman = *Assert(m_node.chainman);
230 
231  {
232  LOCK(::cs_main);
235  }
236 
237  size_t initial_size;
238  size_t initial_total_coins{100};
239 
240  // Make some initial assertions about the contents of the chainstate.
241  {
242  LOCK(::cs_main);
243  CCoinsViewCache& ibd_coinscache = chainman.ActiveChainstate().CoinsTip();
244  initial_size = ibd_coinscache.GetCacheSize();
245  size_t total_coins{0};
246 
247  for (CTransactionRef& txn : m_coinbase_txns) {
248  COutPoint op{txn->GetHash(), 0};
249  BOOST_CHECK(ibd_coinscache.HaveCoin(op));
250  total_coins++;
251  }
252 
253  BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
254  BOOST_CHECK_EQUAL(initial_size, initial_total_coins);
255  }
256 
257  Chainstate& validation_chainstate = chainman.ActiveChainstate();
258 
259  // Snapshot should refuse to load at this height.
260  BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(this));
262 
263  // Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can
264  // be found.
265  constexpr int snapshot_height = 110;
266  mineBlocks(10);
267  initial_size += 10;
268  initial_total_coins += 10;
269 
270  // Should not load malleated snapshots
271  BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
272  this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
273  // A UTXO is missing but count is correct
274  metadata.m_coins_count -= 1;
275 
276  Txid txid;
277  auto_infile >> txid;
278  // coins size
279  (void)ReadCompactSize(auto_infile);
280  // vout index
281  (void)ReadCompactSize(auto_infile);
282  Coin coin;
283  auto_infile >> coin;
284  }));
285 
287 
288  BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
289  this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
290  // Coins count is larger than coins in file
291  metadata.m_coins_count += 1;
292  }));
293  BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
294  this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
295  // Coins count is smaller than coins in file
296  metadata.m_coins_count -= 1;
297  }));
298  BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
299  this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
300  // Wrong hash
301  metadata.m_base_blockhash = uint256::ZERO;
302  }));
303  BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
304  this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
305  // Wrong hash
306  metadata.m_base_blockhash = uint256::ONE;
307  }));
308 
309  BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(this));
311 
312  // Ensure our active chain is the snapshot chainstate.
314 
315  Chainstate& snapshot_chainstate = chainman.ActiveChainstate();
316 
317  {
318  LOCK(::cs_main);
319 
321 
322  // Note: WriteSnapshotBaseBlockhash() is implicitly tested above.
326  }
327 
328  const auto& au_data = ::Params().AssumeutxoForHeight(snapshot_height);
329  const CBlockIndex* tip = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());
330 
331  BOOST_CHECK_EQUAL(tip->m_chain_tx_count, au_data->m_chain_tx_count);
332 
333  // To be checked against later when we try loading a subsequent snapshot.
334  uint256 loaded_snapshot_blockhash{*Assert(WITH_LOCK(chainman.GetMutex(), return chainman.CurrentChainstate().m_from_snapshot_blockhash))};
335 
336  // Make some assertions about the both chainstates. These checks ensure the
337  // legacy chainstate hasn't changed and that the newly created chainstate
338  // reflects the expected content.
339  {
340  LOCK(::cs_main);
341  int chains_tested{0};
342 
343  for (const auto& chainstate : chainman.m_chainstates) {
344  BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
345  CCoinsViewCache& coinscache = chainstate->CoinsTip();
346 
347  // Both caches will be empty initially.
348  BOOST_CHECK_EQUAL((unsigned int)0, coinscache.GetCacheSize());
349 
350  size_t total_coins{0};
351 
352  for (CTransactionRef& txn : m_coinbase_txns) {
353  COutPoint op{txn->GetHash(), 0};
354  BOOST_CHECK(coinscache.HaveCoin(op));
355  total_coins++;
356  }
357 
358  BOOST_CHECK_EQUAL(initial_size , coinscache.GetCacheSize());
359  BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
360  chains_tested++;
361  }
362 
363  BOOST_CHECK_EQUAL(chains_tested, 2);
364  }
365 
366  // Mine some new blocks on top of the activated snapshot chainstate.
367  constexpr size_t new_coins{100};
368  mineBlocks(new_coins); // Defined in TestChain100Setup.
369 
370  {
371  LOCK(::cs_main);
372  size_t coins_in_active{0};
373  size_t coins_in_background{0};
374  size_t coins_missing_from_background{0};
375 
376  for (const auto& chainstate : chainman.m_chainstates) {
377  BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
378  CCoinsViewCache& coinscache = chainstate->CoinsTip();
379  bool is_background = chainstate.get() != &chainman.ActiveChainstate();
380 
381  for (CTransactionRef& txn : m_coinbase_txns) {
382  COutPoint op{txn->GetHash(), 0};
383  if (coinscache.HaveCoin(op)) {
384  (is_background ? coins_in_background : coins_in_active)++;
385  } else if (is_background) {
386  coins_missing_from_background++;
387  }
388  }
389  }
390 
391  BOOST_CHECK_EQUAL(coins_in_active, initial_total_coins + new_coins);
392  BOOST_CHECK_EQUAL(coins_in_background, initial_total_coins);
393  BOOST_CHECK_EQUAL(coins_missing_from_background, new_coins);
394  }
395 
396  // Snapshot should refuse to load after one has already loaded.
397  BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(this));
398 
399  // Snapshot blockhash should be unchanged.
402  loaded_snapshot_blockhash);
403  return std::make_tuple(&validation_chainstate, &snapshot_chainstate);
404  }
405 
406  // Simulate a restart of the node by flushing all state to disk, clearing the
407  // existing ChainstateManager, and unloading the block index.
408  //
409  // @returns a reference to the "restarted" ChainstateManager
411  {
412  ChainstateManager& chainman = *Assert(m_node.chainman);
413 
414  BOOST_TEST_MESSAGE("Simulating node restart");
415  {
416  LOCK(chainman.GetMutex());
417  for (const auto& cs : chainman.m_chainstates) {
418  if (cs->CanFlushToDisk()) cs->ForceFlushStateToDisk();
419  }
420  }
421  {
422  // Process all callbacks referring to the old manager before wiping it.
423  m_node.validation_signals->SyncWithValidationInterfaceQueue();
424  LOCK(::cs_main);
425  chainman.ResetChainstates();
426  BOOST_CHECK_EQUAL(chainman.m_chainstates.size(), 0);
427  m_node.notifications = std::make_unique<KernelNotifications>(Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings));
428  const ChainstateManager::Options chainman_opts{
429  .chainparams = ::Params(),
430  .datadir = chainman.m_options.datadir,
431  .notifications = *m_node.notifications,
432  .signals = m_node.validation_signals.get(),
433  };
434  const BlockManager::Options blockman_opts{
435  .chainparams = chainman_opts.chainparams,
436  .blocks_dir = m_args.GetBlocksDirPath(),
437  .notifications = chainman_opts.notifications,
438  .block_tree_db_params = DBParams{
439  .path = chainman.m_options.datadir / "blocks" / "index",
440  .cache_bytes = m_kernel_cache_sizes.block_tree_db,
441  .memory_only = m_block_tree_db_in_memory,
442  },
443  };
444  // For robustness, ensure the old manager is destroyed before creating a
445  // new one.
446  m_node.chainman.reset();
447  m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown_signal), chainman_opts, blockman_opts);
448  }
449  return *Assert(m_node.chainman);
450  }
451 };
452 
454 BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, SnapshotTestSetup)
455 {
456  this->SetupSnapshot();
457 }
458 
469 BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
470 {
471  ChainstateManager& chainman = *Assert(m_node.chainman);
472  Chainstate& cs1 = chainman.ActiveChainstate();
473 
474  int num_indexes{0};
475  // Blocks in range [assumed_valid_start_idx, last_assumed_valid_idx) will be
476  // marked as assumed-valid and not having data.
477  const int expected_assumed_valid{20};
478  const int last_assumed_valid_idx{111};
479  const int assumed_valid_start_idx = last_assumed_valid_idx - expected_assumed_valid;
480 
481  // Mine to height 120, past the hardcoded regtest assumeutxo snapshot at
482  // height 110
483  mineBlocks(20);
484 
485  CBlockIndex* validated_tip{nullptr};
486  CBlockIndex* assumed_base{nullptr};
487  CBlockIndex* assumed_tip{WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip())};
488  BOOST_CHECK_EQUAL(assumed_tip->nHeight, 120);
489 
490  auto reload_all_block_indexes = [&]() {
491  LOCK(chainman.GetMutex());
492  // For completeness, we also reset the block sequence counters to
493  // ensure that no state which affects the ranking of tip-candidates is
494  // retained (even though this isn't strictly necessary).
495  chainman.ResetBlockSequenceCounters();
496  for (const auto& cs : chainman.m_chainstates) {
497  cs->ClearBlockIndexCandidates();
498  BOOST_CHECK(cs->setBlockIndexCandidates.empty());
499  }
500  chainman.LoadBlockIndex();
501  for (const auto& cs : chainman.m_chainstates) {
502  cs->PopulateBlockIndexCandidates();
503  }
504  };
505 
506  // Ensure that without any assumed-valid BlockIndex entries, only the current tip is
507  // considered as a candidate.
508  reload_all_block_indexes();
510 
511  // Reset some region of the chain's nStatus, removing the HAVE_DATA flag.
512  for (int i = 0; i <= cs1.m_chain.Height(); ++i) {
513  LOCK(::cs_main);
514  auto index = cs1.m_chain[i];
515 
516  // Blocks with heights in range [91, 110] are marked as missing data.
517  if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) {
518  index->nStatus = BlockStatus::BLOCK_VALID_TREE;
519  index->nTx = 0;
520  index->m_chain_tx_count = 0;
521  }
522 
523  ++num_indexes;
524 
525  // Note the last fully-validated block as the expected validated tip.
526  if (i == (assumed_valid_start_idx - 1)) {
527  validated_tip = index;
528  }
529  // Note the last assumed valid block as the snapshot base
530  if (i == last_assumed_valid_idx - 1) {
531  assumed_base = index;
532  }
533  }
534 
535  // Note: cs2's tip is not set when ActivateExistingSnapshot is called.
536  Chainstate& cs2{WITH_LOCK(::cs_main, return chainman.AddChainstate(std::make_unique<Chainstate>(nullptr, chainman.m_blockman, chainman, *assumed_base->phashBlock)))};
537 
538  // Set tip of the fully validated chain to be the validated tip
539  cs1.m_chain.SetTip(*validated_tip);
540 
541  // Set tip of the assume-valid-based chain to the assume-valid block
542  cs2.m_chain.SetTip(*assumed_base);
543 
544  // Sanity check test variables.
545  BOOST_CHECK_EQUAL(num_indexes, 121); // 121 total blocks, including genesis
546  BOOST_CHECK_EQUAL(assumed_tip->nHeight, 120); // original chain has height 120
547  BOOST_CHECK_EQUAL(validated_tip->nHeight, 90); // current cs1 chain has height 90
548  BOOST_CHECK_EQUAL(assumed_base->nHeight, 110); // current cs2 chain has height 110
549 
550  // Regenerate cs1.setBlockIndexCandidates and cs2.setBlockIndexCandidate and
551  // check contents below.
552  reload_all_block_indexes();
553 
554  // The fully validated chain should only have the current validated tip and
555  // the assumed valid base as candidates, blocks 90 and 110. Specifically:
556  //
557  // - It does not have blocks 0-89 because they contain less work than the
558  // chain tip.
559  //
560  // - It has block 90 because it has data and equal work to the chain tip,
561  // (since it is the chain tip).
562  //
563  // - It does not have blocks 91-109 because they do not contain data.
564  //
565  // - It has block 110 even though it does not have data, because
566  // LoadBlockIndex has a special case to always add the snapshot block as a
567  // candidate. The special case is only actually intended to apply to the
568  // snapshot chainstate cs2, not the background chainstate cs1, but it is
569  // written broadly and applies to both.
570  //
571  // - It does not have any blocks after height 110 because cs1 is a background
572  // chainstate, and only blocks where are ancestors of the snapshot block
573  // are added as candidates for the background chainstate.
575  BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.count(validated_tip), 1);
576  BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.count(assumed_base), 1);
577 
578  // The assumed-valid tolerant chain has the assumed valid base as a
579  // candidate, but otherwise has none of the assumed-valid (which do not
580  // HAVE_DATA) blocks as candidates.
581  //
582  // Specifically:
583  // - All blocks below height 110 are not candidates, because cs2 chain tip
584  // has height 110 and they have less work than it does.
585  //
586  // - Block 110 is a candidate even though it does not have data, because it
587  // is the snapshot block, which is assumed valid.
588  //
589  // - Blocks 111-120 are added because they have data.
590 
591  // Check that block 90 is absent
592  BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(validated_tip), 0);
593  // Check that block 109 is absent
594  BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_base->pprev), 0);
595  // Check that block 110 is present
596  BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_base), 1);
597  // Check that block 120 is present
598  BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_tip), 1);
599  // Check that 11 blocks total are present.
600  BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes - last_assumed_valid_idx + 1);
601 }
602 
603 BOOST_FIXTURE_TEST_CASE(loadblockindex_invalid_descendants, TestChain100Setup)
604 {
605  LOCK(Assert(m_node.chainman)->GetMutex());
606  // consider the chain of blocks grand_parent <- parent <- child
607  // intentionally mark:
608  // - grand_parent: BLOCK_FAILED_VALID
609  // - parent: BLOCK_FAILED_CHILD
610  // - child: not invalid
611  // Test that when the block index is loaded, all blocks are marked as BLOCK_FAILED_VALID
612  auto* child{m_node.chainman->ActiveChain().Tip()};
613  auto* parent{child->pprev};
614  auto* grand_parent{parent->pprev};
615  grand_parent->nStatus = (grand_parent->nStatus | BLOCK_FAILED_VALID);
616  parent->nStatus = (parent->nStatus & ~BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;
617  child->nStatus = (child->nStatus & ~BLOCK_FAILED_VALID);
618 
619  // Reload block index to recompute block status validity flags.
620  m_node.chainman->LoadBlockIndex();
621 
622  // check grand_parent, parent, child is marked as BLOCK_FAILED_VALID after reloading the block index
623  BOOST_CHECK(grand_parent->nStatus & BLOCK_FAILED_VALID);
624  BOOST_CHECK(parent->nStatus & BLOCK_FAILED_VALID);
625  BOOST_CHECK(child->nStatus & BLOCK_FAILED_VALID);
626 }
627 
630 BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_init, SnapshotTestSetup)
631 {
632  ChainstateManager& chainman = *Assert(m_node.chainman);
633  Chainstate& bg_chainstate = chainman.ActiveChainstate();
634 
635  this->SetupSnapshot();
636 
637  fs::path snapshot_chainstate_dir = *node::FindAssumeutxoChainstateDir(chainman.m_options.datadir);
638  BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
639  BOOST_CHECK_EQUAL(snapshot_chainstate_dir, gArgs.GetDataDirNet() / "chainstate_snapshot");
640 
642  const uint256 snapshot_tip_hash = WITH_LOCK(chainman.GetMutex(),
643  return chainman.ActiveTip()->GetBlockHash());
644 
645  BOOST_CHECK_EQUAL(WITH_LOCK(chainman.GetMutex(), return chainman.m_chainstates.size()), 2);
646 
647  // "Rewind" the background chainstate so that its tip is not at the
648  // base block of the snapshot - this is so after simulating a node restart,
649  // it will initialize instead of attempting to complete validation.
650  //
651  // Note that this is not a realistic use of DisconnectTip().
653  BlockValidationState unused_state;
654  {
655  LOCK2(::cs_main, bg_chainstate.MempoolMutex());
656  BOOST_CHECK(bg_chainstate.DisconnectTip(unused_state, &unused_pool));
657  unused_pool.clear(); // to avoid queuedTx assertion errors on teardown
658  }
659  BOOST_CHECK_EQUAL(bg_chainstate.m_chain.Height(), 109);
660 
661  // Test that simulating a shutdown (resetting ChainstateManager) and then performing
662  // chainstate reinitializing successfully reloads both chainstates.
663  ChainstateManager& chainman_restarted = this->SimulateNodeRestart();
664 
665  BOOST_TEST_MESSAGE("Performing Load/Verify/Activate of chainstate");
666 
667  // This call reinitializes the chainstates.
668  this->LoadVerifyActivateChainstate();
669 
670  {
671  LOCK(chainman_restarted.GetMutex());
672  BOOST_CHECK_EQUAL(chainman_restarted.m_chainstates.size(), 2);
673  // Background chainstate has height of 109 not 110 here due to a quirk
674  // of the LoadVerifyActivate only calling ActivateBestChain on one
675  // chainstate. The height would be 110 after a real restart, but it's
676  // fine for this test which is focused on the snapshot chainstate.
677  BOOST_CHECK_EQUAL(chainman_restarted.m_chainstates[0]->m_chain.Height(), 109);
678  BOOST_CHECK_EQUAL(chainman_restarted.m_chainstates[1]->m_chain.Height(), 210);
679 
680  BOOST_CHECK(chainman_restarted.CurrentChainstate().m_from_snapshot_blockhash);
681  BOOST_CHECK(chainman_restarted.CurrentChainstate().m_assumeutxo == Assumeutxo::UNVALIDATED);
682 
683  BOOST_CHECK_EQUAL(chainman_restarted.ActiveTip()->GetBlockHash(), snapshot_tip_hash);
684  BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 210);
685  BOOST_CHECK_EQUAL(chainman_restarted.HistoricalChainstate()->m_chain.Height(), 109);
686  }
687 
688  BOOST_TEST_MESSAGE(
689  "Ensure we can mine blocks on top of the initialized snapshot chainstate");
690  mineBlocks(10);
691  {
692  LOCK(chainman_restarted.GetMutex());
693  BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 220);
694 
695  // Background chainstate should be unaware of new blocks on the snapshot
696  // chainstate, but the block disconnected above is now reattached.
697  BOOST_CHECK_EQUAL(chainman_restarted.m_chainstates.size(), 2);
698  BOOST_CHECK_EQUAL(chainman_restarted.m_chainstates[0]->m_chain.Height(), 110);
699  BOOST_CHECK_EQUAL(chainman_restarted.m_chainstates[1]->m_chain.Height(), 220);
700  BOOST_CHECK_EQUAL(chainman_restarted.HistoricalChainstate(), nullptr);
701  }
702 }
703 
704 BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion, SnapshotTestSetup)
705 {
706  this->SetupSnapshot();
707 
708  ChainstateManager& chainman = *Assert(m_node.chainman);
709  Chainstate& active_cs = chainman.ActiveChainstate();
710  Chainstate& validated_cs{*Assert(WITH_LOCK(cs_main, return chainman.HistoricalChainstate()))};
711  auto tip_cache_before_complete = active_cs.m_coinstip_cache_size_bytes;
712  auto db_cache_before_complete = active_cs.m_coinsdb_cache_size_bytes;
713 
715  m_node.notifications->m_shutdown_on_fatal_error = false;
716 
717  fs::path snapshot_chainstate_dir = *node::FindAssumeutxoChainstateDir(chainman.m_options.datadir);
718  BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
719  BOOST_CHECK_EQUAL(snapshot_chainstate_dir, gArgs.GetDataDirNet() / "chainstate_snapshot");
720 
722  const uint256 snapshot_tip_hash = WITH_LOCK(chainman.GetMutex(),
723  return chainman.ActiveTip()->GetBlockHash());
724 
725  res = WITH_LOCK(::cs_main, return chainman.MaybeValidateSnapshot(validated_cs, active_cs));
727 
728  BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.CurrentChainstate().m_assumeutxo == Assumeutxo::VALIDATED));
730  BOOST_CHECK_EQUAL(WITH_LOCK(chainman.GetMutex(), return chainman.HistoricalChainstate()), nullptr);
731 
732  // Cache should have been rebalanced and reallocated to the "only" remaining
733  // chainstate.
734  BOOST_CHECK(active_cs.m_coinstip_cache_size_bytes > tip_cache_before_complete);
735  BOOST_CHECK(active_cs.m_coinsdb_cache_size_bytes > db_cache_before_complete);
736 
737  // Trying completion again should return false.
738  res = WITH_LOCK(::cs_main, return chainman.MaybeValidateSnapshot(validated_cs, active_cs));
740 
741  // The invalid snapshot path should not have been used.
742  fs::path snapshot_invalid_dir = gArgs.GetDataDirNet() / "chainstate_snapshot_INVALID";
743  BOOST_CHECK(!fs::exists(snapshot_invalid_dir));
744  // chainstate_snapshot should still exist.
745  BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
746 
747  // Test that simulating a shutdown (resetting ChainstateManager) and then performing
748  // chainstate reinitializing successfully cleans up the background-validation
749  // chainstate data, and we end up with a single chainstate that is at tip.
750  ChainstateManager& chainman_restarted = this->SimulateNodeRestart();
751 
752  BOOST_TEST_MESSAGE("Performing Load/Verify/Activate of chainstate");
753 
754  // This call reinitializes the chainstates, and should clean up the now unnecessary
755  // background-validation leveldb contents.
756  this->LoadVerifyActivateChainstate();
757 
758  BOOST_CHECK(!fs::exists(snapshot_invalid_dir));
759  // chainstate_snapshot should now *not* exist.
760  BOOST_CHECK(!fs::exists(snapshot_chainstate_dir));
761 
762  const Chainstate& active_cs2 = chainman_restarted.ActiveChainstate();
763 
764  {
765  LOCK(chainman_restarted.GetMutex());
766  BOOST_CHECK_EQUAL(chainman_restarted.m_chainstates.size(), 1);
768  BOOST_CHECK(active_cs2.m_coinstip_cache_size_bytes > tip_cache_before_complete);
769  BOOST_CHECK(active_cs2.m_coinsdb_cache_size_bytes > db_cache_before_complete);
770 
771  BOOST_CHECK_EQUAL(chainman_restarted.ActiveTip()->GetBlockHash(), snapshot_tip_hash);
772  BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 210);
773  }
774 
775  BOOST_TEST_MESSAGE(
776  "Ensure we can mine blocks on top of the \"new\" IBD chainstate");
777  mineBlocks(10);
778  {
779  LOCK(chainman_restarted.GetMutex());
780  BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 220);
781  }
782 }
783 
784 BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, SnapshotTestSetup)
785 {
786  auto chainstates = this->SetupSnapshot();
787  Chainstate& validation_chainstate = *std::get<0>(chainstates);
788  Chainstate& unvalidated_cs = *std::get<1>(chainstates);
789  ChainstateManager& chainman = *Assert(m_node.chainman);
791  m_node.notifications->m_shutdown_on_fatal_error = false;
792 
793  // Test tampering with the IBD UTXO set with an extra coin to ensure it causes
794  // snapshot completion to fail.
795  CCoinsViewCache& ibd_coins = WITH_LOCK(::cs_main,
796  return validation_chainstate.CoinsTip());
797  Coin badcoin;
798  badcoin.out.nValue = m_rng.rand32();
799  badcoin.nHeight = 1;
800  badcoin.out.scriptPubKey.assign(m_rng.randbits(6), 0);
801  Txid txid = Txid::FromUint256(m_rng.rand256());
802  ibd_coins.AddCoin(COutPoint(txid, 0), std::move(badcoin), false);
803 
804  fs::path snapshot_chainstate_dir = gArgs.GetDataDirNet() / "chainstate_snapshot";
805  BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
806 
807  {
808  ASSERT_DEBUG_LOG("failed to validate the -assumeutxo snapshot state");
809  res = WITH_LOCK(::cs_main, return chainman.MaybeValidateSnapshot(validation_chainstate, unvalidated_cs));
811  }
812 
813  {
814  LOCK(chainman.GetMutex());
815  BOOST_CHECK_EQUAL(chainman.m_chainstates.size(), 2);
816  BOOST_CHECK(chainman.m_chainstates[0]->m_assumeutxo == Assumeutxo::VALIDATED);
817  BOOST_CHECK(!chainman.m_chainstates[0]->SnapshotBase());
818  BOOST_CHECK(chainman.m_chainstates[1]->m_assumeutxo == Assumeutxo::INVALID);
819  BOOST_CHECK(chainman.m_chainstates[1]->SnapshotBase());
820  }
821 
822  fs::path snapshot_invalid_dir = gArgs.GetDataDirNet() / "chainstate_snapshot_INVALID";
823  BOOST_CHECK(fs::exists(snapshot_invalid_dir));
824 
825  // Test that simulating a shutdown (resetting ChainstateManager) and then performing
826  // chainstate reinitializing successfully loads only the fully-validated
827  // chainstate data, and we end up with a single chainstate that is at tip.
828  ChainstateManager& chainman_restarted = this->SimulateNodeRestart();
829 
830  BOOST_TEST_MESSAGE("Performing Load/Verify/Activate of chainstate");
831 
832  // This call reinitializes the chainstates, and should clean up the now unnecessary
833  // background-validation leveldb contents.
834  this->LoadVerifyActivateChainstate();
835 
836  BOOST_CHECK(fs::exists(snapshot_invalid_dir));
837  BOOST_CHECK(!fs::exists(snapshot_chainstate_dir));
838 
839  {
840  LOCK(::cs_main);
841  BOOST_CHECK_EQUAL(chainman_restarted.m_chainstates.size(), 1);
843  BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 210);
844  }
845 
846  BOOST_TEST_MESSAGE(
847  "Ensure we can mine blocks on top of the \"new\" IBD chainstate");
848  mineBlocks(10);
849  {
850  LOCK(::cs_main);
851  BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 220);
852  }
853 }
854 
856 template <typename Options>
858  const std::vector<const char*>& args)
859 {
860  const auto argv{Cat({"ignore"}, args)};
861  std::string error{};
862  if (!args_man.ParseParameters(argv.size(), argv.data(), error)) {
863  return util::Error{Untranslated("ParseParameters failed with error: " + error)};
864  }
865  const auto result{node::ApplyArgsManOptions(args_man, opts)};
867  return opts;
868 }
869 
871 {
873  auto get_opts = [&](const std::vector<const char*>& args) {
874  static kernel::Notifications notifications{};
875  static const ChainstateManager::Options options{
876  .chainparams = ::Params(),
877  .datadir = {},
878  .notifications = notifications};
879  return SetOptsFromArgs(*this->m_node.args, options, args);
880  };
882  auto get_valid_opts = [&](const std::vector<const char*>& args) {
883  const auto result{get_opts(args)};
884  BOOST_REQUIRE_MESSAGE(result, util::ErrorString(result).original);
885  return *result;
886  };
887 
888  // test -assumevalid
889  BOOST_CHECK(!get_valid_opts({}).assumed_valid_block);
890  BOOST_CHECK_EQUAL(get_valid_opts({"-assumevalid="}).assumed_valid_block, uint256::ZERO);
891  BOOST_CHECK_EQUAL(get_valid_opts({"-assumevalid=0"}).assumed_valid_block, uint256::ZERO);
892  BOOST_CHECK_EQUAL(get_valid_opts({"-noassumevalid"}).assumed_valid_block, uint256::ZERO);
893  BOOST_CHECK_EQUAL(get_valid_opts({"-assumevalid=0x12"}).assumed_valid_block, uint256{0x12});
894 
895  std::string assume_valid{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"};
896  BOOST_CHECK_EQUAL(get_valid_opts({("-assumevalid=" + assume_valid).c_str()}).assumed_valid_block, uint256::FromHex(assume_valid));
897 
898  BOOST_CHECK(!get_opts({"-assumevalid=xyz"})); // invalid hex characters
899  BOOST_CHECK(!get_opts({"-assumevalid=01234567890123456789012345678901234567890123456789012345678901234"})); // > 64 hex chars
900 
901  // test -minimumchainwork
902  BOOST_CHECK(!get_valid_opts({}).minimum_chain_work);
903  BOOST_CHECK_EQUAL(get_valid_opts({"-minimumchainwork=0"}).minimum_chain_work, arith_uint256());
904  BOOST_CHECK_EQUAL(get_valid_opts({"-nominimumchainwork"}).minimum_chain_work, arith_uint256());
905  BOOST_CHECK_EQUAL(get_valid_opts({"-minimumchainwork=0x1234"}).minimum_chain_work, arith_uint256{0x1234});
906 
907  std::string minimum_chainwork{"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"};
908  BOOST_CHECK_EQUAL(get_valid_opts({("-minimumchainwork=" + minimum_chainwork).c_str()}).minimum_chain_work, UintToArith256(uint256::FromHex(minimum_chainwork).value()));
909 
910  BOOST_CHECK(!get_opts({"-minimumchainwork=xyz"})); // invalid hex characters
911  BOOST_CHECK(!get_opts({"-minimumchainwork=01234567890123456789012345678901234567890123456789012345678901234"})); // > 64 hex chars
912 }
913 
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:686
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: chain.h:118
CAmount nValue
Definition: transaction.h:142
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1038
const std::optional< uint256 > m_from_snapshot_blockhash
The blockhash which is the base of the snapshot this chainstate was created from. ...
Definition: validation.h:637
Testing setup that performs all steps up until right before ChainstateManager gets initialized...
Definition: setup_common.h:106
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:35
kernel::CacheSizes m_kernel_cache_sizes
Definition: setup_common.h:107
The assumeutxo snapshot failed validation.
static const uint256 ONE
Definition: uint256.h:204
std::unique_ptr< node::Warnings > warnings
Manages all the node warnings.
Definition: context.h:91
const Options m_options
Definition: validation.h:1035
std::set< CBlockIndex *, node::CBlockIndexWorkComparator > setBlockIndexCandidates
The set of all CBlockIndex entries that have as much work as our current tip or more, and transaction data needed to be validated (with BLOCK_VALID_TRANSACTIONS for each block and its parents back to the genesis block or an assumeutxo snapshot block).
Definition: validation.h:683
assert(!tx.IsCoinBase())
Unused flag that was previously set when descending from failed block.
Definition: chain.h:80
util::SignalInterrupt * shutdown_signal
Interrupt object used to track whether node shutdown was requested.
Definition: context.h:65
A UTXO entry.
Definition: coins.h:34
uint64_t ReadCompactSize(Stream &is, bool range_check=true)
Decode a CompactSize-encoded variable-length integer.
Definition: serialize.h:330
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
Definition: validation.h:939
node::NodeContext m_node
Definition: bitcoin-gui.cpp:43
bool m_block_tree_db_in_memory
Definition: setup_common.h:109
util::Result< Options > SetOptsFromArgs(ArgsManager &args_man, Options opts, const std::vector< const char *> &args)
Helper function to parse args into args_man and return the result of applying them to opts...
ArgsManager m_args
Test-specific arguments and settings.
Definition: setup_common.h:99
std::optional< uint256 > ReadSnapshotBaseBlockhash(fs::path chaindir)
size_t m_coinsdb_cache_size_bytes
The cache size of the on-disk coins view.
Definition: validation.h:718
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:82
std::atomic< int > exit_status
Definition: context.h:89
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1165
All parent headers found, difficulty matches, timestamp >= median previous.
Definition: chain.h:51
std::tuple< Chainstate *, Chainstate * > SetupSnapshot()
int Height() const
Return the maximal height in the chain.
Definition: chain.h:425
CTxOut out
unspent transaction output
Definition: coins.h:38
std::unique_ptr< ValidationSignals > validation_signals
Issues calls about blocks and transactions.
Definition: context.h:88
stage after last reached validness failed
Definition: chain.h:79
std::vector< CTransactionRef > m_coinbase_txns
Definition: setup_common.h:241
An options struct for ChainstateManager, more ergonomically referred to as ChainstateManager::Options...
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:177
size_t m_total_coinsdb_cache
The total number of bytes available for us to use across all leveldb coins databases.
Definition: validation.h:1086
uint32_t nTime
Definition: chain.h:142
uint64_t m_coins_count
The number of coins in the UTXO set contained in this snapshot.
Definition: utxo_snapshot.h:50
util::Result< void > ApplyArgsManOptions(const ArgsManager &args, BlockManager::Options &opts)
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:625
static const unsigned int MAX_DISCONNECTED_TX_POOL_BYTES
Maximum bytes for transactions to store for processing during reorg.
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:372
void SetTip(CBlockIndex &block)
Set/initialize a chain with a given tip.
Definition: chain.cpp:16
arith_uint256 UintToArith256(const uint256 &a)
Basic testing setup.
Definition: setup_common.h:64
std::unique_ptr< CTxMemPool > mempool
Definition: context.h:68
uint256 GetBlockHash() const
Definition: chain.h:198
unsigned int GetCacheSize() const
Size of the cache (in number of transaction outputs)
Definition: coins.cpp:325
#define LOCK2(cs1, cs2)
Definition: sync.h:259
static bool exists(const path &p)
Definition: fs.h:95
bool DisconnectTip(BlockValidationState &state, DisconnectedBlockTransactions *disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main
Disconnect m_chain&#39;s tip.
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:239
ArgsManager & args
Definition: bitcoind.cpp:277
Blocks after an assumeutxo snapshot have been validated but the snapshot itself has not been validate...
Chainstate stores and provides an API to update our local knowledge of the current best chain...
Definition: validation.h:550
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_FIXTURE_TEST_CASE(chainstatemanager, TestChain100Setup)
Basic tests for ChainstateManager.
uint64_t m_chain_tx_count
(memory only) Number of transactions in the chain up to and including this block. ...
Definition: chain.h:129
#define LOCK(cs)
Definition: sync.h:258
ArgsManager * args
Definition: context.h:74
fs::path GetBlocksDirPath() const
Get blocks directory path.
Definition: args.cpp:286
bool LoadBlockIndex() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Load the block tree and coins database from disk, initializing state if we&#39;re running with -reindex...
SnapshotCompletionResult
Definition: validation.h:902
BOOST_AUTO_TEST_SUITE_END()
static std::optional< uint256 > FromHex(std::string_view str)
Definition: uint256.h:197
static const uint256 ZERO
Definition: uint256.h:203
SnapshotCompletionResult MaybeValidateSnapshot(Chainstate &validated_cs, Chainstate &unvalidated_cs) EXCLUSIVE_LOCKS_REQUIRED(Chainstate & CurrentChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Try to validate an assumeutxo snapshot by using a validated historical chainstate targeted at the sna...
Definition: validation.h:1119
void mineBlocks(int num_blocks)
Mine a series of new blocks on the active chain.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1167
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:191
Every block in the chain has been validated.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
Definition: validation.h:1032
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition: setup_common.h:146
#define ASSERT_DEBUG_LOG(message)
Definition: logging.h:42
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
A base class defining functions for notifying about certain kernel events.
size_t m_total_coinstip_cache
The total number of bytes available for us to use across all in-memory coins caches.
Definition: validation.h:1082
DisconnectedBlockTransactions.
size_t block_tree_db
Definition: caches.h:24
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:289
256-bit unsigned big integer.
void AddCoin(const COutPoint &outpoint, Coin &&coin, bool possible_overwrite)
Add a coin.
Definition: coins.cpp:89
ArgsManager gArgs
Definition: args.cpp:40
uint256 m_base_blockhash
The hash of the block that reflects the tip of the chain for the UTXO set contained in this snapshot...
Definition: utxo_snapshot.h:45
256-bit opaque blob.
Definition: uint256.h:195
auto result
Definition: common-types.h:74
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:93
const CChainParams & Params()
Return the currently selected parameters.
static transaction_identifier FromUint256(const uint256 &id)
static bool CreateAndActivateUTXOSnapshot(TestingSetup *fixture, F malleation=NoMalleation, bool reset_chainstate=false, bool in_memory_chainstate=false)
Create and activate a UTXO snapshot, optionally providing a function to malleate the snapshot...
Definition: chainstate.h:33
std::unique_ptr< KernelNotifications > notifications
Issues blocking calls about sync status, errors and warnings.
Definition: context.h:86
void ResetBlockSequenceCounters() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1066
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:396
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1166
Application-specific storage settings.
Definition: dbwrapper.h:33
static void pool cs
std::optional< fs::path > FindAssumeutxoChainstateDir(const fs::path &data_dir)
Return a path to the snapshot-based chainstate dir, if one exists.
bilingual_str ErrorString(const Result< T > &result)
Definition: result.h:93
size_t m_coinstip_cache_size_bytes
The cache size of the in-memory coins view.
Definition: validation.h:721
Chainstate & ActiveChainstate() const
Alternatives to CurrentChainstate() used by older code to query latest chainstate information without...
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:367
Chainstate * HistoricalChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Return historical chainstate targeting a specific block, if any.
Definition: validation.h:1128
std::optional< AssumeutxoData > AssumeutxoForHeight(int height) const
Definition: chainparams.h:119
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: cs_main.cpp:8
node::NodeContext m_node
Definition: setup_common.h:66
std::function< bool()> shutdown_request
Function to request a shutdown.
Definition: context.h:63
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
V Cat(V v1, V &&v2)
Concatenate two vectors, moving elements.
Definition: vector.h:34
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:37
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: coins.cpp:188