coinstatsindex_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 <chain.h>
   6  #include <chainparams.h>
   7  #include <coins.h>
   8  #include <consensus/validation.h>
   9  #include <index/coinstatsindex.h>
  10  #include <interfaces/chain.h>
  11  #include <kernel/coinstats.h>
  12  #include <kernel/types.h>
  13  #include <key.h>
  14  #include <primitives/block.h>
  15  #include <primitives/transaction.h>
  16  #include <script/script.h>
  17  #include <sync.h>
  18  #include <test/util/setup_common.h>
  19  #include <test/util/validation.h>
  20  #include <util/check.h>
  21  #include <validation.h>
  22  
  23  #include <boost/test/unit_test.hpp>
  24  
  25  #include <memory>
  26  #include <optional>
  27  #include <span>
  28  #include <vector>
  29  
  30  using kernel::ChainstateRole;
  31  
  32  BOOST_AUTO_TEST_SUITE(coinstatsindex_tests)
  33  
  34  BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
  35  {
  36      CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1_MiB, true};
  37      BOOST_REQUIRE(coin_stats_index.Init());
  38  
  39      const CBlockIndex* block_index;
  40      {
  41          LOCK(cs_main);
  42          block_index = m_node.chainman->ActiveChain().Tip();
  43      }
  44  
  45      // CoinStatsIndex should not be found before it is started.
  46      BOOST_CHECK(!coin_stats_index.LookUpStats(*block_index));
  47  
  48      // BlockUntilSyncedToCurrentChain should return false before CoinStatsIndex
  49      // is started.
  50      BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
  51  
  52      coin_stats_index.Sync();
  53  
  54      // Check that CoinStatsIndex works for genesis block.
  55      const CBlockIndex* genesis_block_index;
  56      {
  57          LOCK(cs_main);
  58          genesis_block_index = m_node.chainman->ActiveChain().Genesis();
  59      }
  60      BOOST_CHECK(coin_stats_index.LookUpStats(*genesis_block_index));
  61  
  62      // Check that CoinStatsIndex updates with new blocks.
  63      BOOST_CHECK(coin_stats_index.LookUpStats(*block_index));
  64  
  65      const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};
  66      std::vector<CMutableTransaction> noTxns;
  67      CreateAndProcessBlock(noTxns, script_pub_key);
  68  
  69      // Let the CoinStatsIndex to catch up again.
  70      BOOST_CHECK(coin_stats_index.BlockUntilSyncedToCurrentChain());
  71  
  72      const CBlockIndex* new_block_index;
  73      {
  74          LOCK(cs_main);
  75          new_block_index = m_node.chainman->ActiveChain().Tip();
  76      }
  77      BOOST_CHECK(coin_stats_index.LookUpStats(*new_block_index));
  78  
  79      BOOST_CHECK(block_index != new_block_index);
  80  
  81      // Shutdown sequence (c.f. Shutdown() in init.cpp)
  82      coin_stats_index.Stop();
  83  }
  84  
  85  // Test shutdown between BlockConnected and ChainStateFlushed notifications,
  86  // make sure index is not corrupted and is able to reload.
  87  BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
  88  {
  89      Chainstate& chainstate = Assert(m_node.chainman)->ActiveChainstate();
  90      const CChainParams& params = Params();
  91      {
  92          CoinStatsIndex index{interfaces::MakeChain(m_node), 1_MiB};
  93          BOOST_REQUIRE(index.Init());
  94          index.Sync();
  95          std::shared_ptr<const CBlock> new_block;
  96          CBlockIndex* new_block_index = nullptr;
  97          {
  98              const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};
  99              const CBlock block = this->CreateBlock({}, script_pub_key);
 100  
 101              new_block = std::make_shared<CBlock>(block);
 102  
 103              LOCK(cs_main);
 104              BlockValidationState state;
 105              BOOST_CHECK(CheckBlock(block, state, params.GetConsensus()));
 106              BOOST_CHECK(m_node.chainman->AcceptBlock(new_block, state, &new_block_index, true, nullptr, nullptr, true));
 107              CCoinsViewCache view(&chainstate.CoinsTip());
 108              BOOST_CHECK(chainstate.ConnectBlock(block, state, new_block_index, view));
 109          }
 110          // Send block connected notification, then stop the index without
 111          // sending a chainstate flushed notification. Prior to #24138, this
 112          // would cause the index to be corrupted and fail to reload.
 113          ValidationInterfaceTest::BlockConnected(ChainstateRole{}, index, new_block, new_block_index);
 114          index.Stop();
 115      }
 116  
 117      {
 118          CoinStatsIndex index{interfaces::MakeChain(m_node), 1_MiB};
 119          BOOST_REQUIRE(index.Init());
 120          // Make sure the index can be loaded.
 121          BOOST_REQUIRE(index.StartBackgroundSync());
 122          index.Stop();
 123      }
 124  }
 125  
 126  BOOST_AUTO_TEST_SUITE_END()
 127