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