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