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