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