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()