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