baseindex_tests.cpp raw

   1  // Copyright (c) 2020-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 <index/coinstatsindex.h>
   6  #include <interfaces/chain.h>
   7  #include <script/script.h>
   8  #include <test/util/setup_common.h>
   9  #include <util/byte_units.h>
  10  #include <util/check.h>
  11  #include <validation.h>
  12  
  13  #include <boost/test/unit_test.hpp>
  14  
  15  // Tests of generic BaseIndex functionality that is independent of which
  16  // concrete index is being used. CoinStatsIndex is used here merely as a
  17  // convenient instantiation of BaseIndex.
  18  BOOST_AUTO_TEST_SUITE(baseindex_tests)
  19  
  20  // Test that the index does not commit ahead of the chainstate's last
  21  // flushed block. If it did, a subsequent unclean shutdown would corrupt
  22  // the index, because during reverting it would require blocks that were
  23  // never flushed to disk.
  24  BOOST_FIXTURE_TEST_CASE(baseindex_no_commit_ahead_of_flush, TestChain100Setup)
  25  {
  26      Chainstate& chainstate = Assert(m_node.chainman)->ActiveChainstate();
  27      auto sync_index = [&](bool do_flush, int expected_sync_height, int expected_commit_height) {
  28          CoinStatsIndex index{interfaces::MakeChain(m_node), /*n_cache_size=*/1_MiB};
  29          BOOST_REQUIRE(index.Init());
  30          index.Sync();
  31          if (do_flush) {
  32              chainstate.ForceFlushStateToDisk();
  33              m_node.chain->context()->validation_signals->SyncWithValidationInterfaceQueue();
  34          }
  35          BOOST_CHECK_EQUAL(index.GetSummary().best_block_height, expected_sync_height);
  36          index.Stop();
  37          // Reload index to see which block data was actually committed.
  38          BOOST_REQUIRE(index.Init());
  39          BOOST_CHECK_EQUAL(index.GetSummary().best_block_height, expected_commit_height);
  40          index.Stop();
  41      };
  42  
  43      // Part 1: Sync, then "crash" (stop without flushing). Models a node that
  44      // started up, had its index catch up, but never flushed before going down.
  45      // The end-of-sync Commit() runs at chain tip (height 100) but
  46      // m_last_flushed_block is null, so it is skipped.
  47      sync_index(false, 100, 0);
  48  
  49      // Part 2: Restart cleanly. Sync, force a chainstate flush, and drain the
  50      // validation queue so the index's ChainStateFlushed callback runs.
  51      // Now m_last_flushed_block == tip == 100 and the index can commit.
  52      sync_index(true, 100, 100);
  53  
  54      // Part 3: Connect a new block on the chain without flushing
  55      // (m_last_flushed_block stays at 100). For a real node this would happen
  56      // in parallel with Sync(). Here we do it before Sync() to make the race
  57      // state deterministic.
  58      CreateAndProcessBlock({}, CScript() << OP_TRUE);
  59      sync_index(false, 101, 100);
  60  }
  61  
  62  BOOST_AUTO_TEST_SUITE_END()
  63