22// Distributed under the MIT software license, see the accompanying
33// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44
5+ #include < chainparams.h>
56#include < index/coinstatsindex.h>
67#include < test/util/setup_common.h>
8+ #include < test/util/validation.h>
79#include < util/time.h>
810#include < validation.h>
911
@@ -16,6 +18,17 @@ using node::CoinStatsHashType;
1618
1719BOOST_AUTO_TEST_SUITE (coinstatsindex_tests)
1820
21+ static void IndexWaitSynced(BaseIndex& index)
22+ {
23+ // Allow the CoinStatsIndex to catch up with the block index that is syncing
24+ // in a background thread.
25+ const auto timeout = GetTime<std::chrono::seconds>() + 120s;
26+ while (!index.BlockUntilSyncedToCurrentChain ()) {
27+ BOOST_REQUIRE (timeout > GetTime<std::chrono::milliseconds>());
28+ UninterruptibleSleep (100ms);
29+ }
30+ }
31+
1932BOOST_FIXTURE_TEST_CASE (coinstatsindex_initial_sync, TestChain100Setup)
2033{
2134 CoinStatsIndex coin_stats_index{1 << 20 , true };
@@ -36,13 +49,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
3649
3750 BOOST_REQUIRE (coin_stats_index.Start (m_node.chainman ->ActiveChainstate ()));
3851
39- // Allow the CoinStatsIndex to catch up with the block index that is syncing
40- // in a background thread.
41- const auto timeout = GetTime<std::chrono::seconds>() + 120s;
42- while (!coin_stats_index.BlockUntilSyncedToCurrentChain ()) {
43- BOOST_REQUIRE (timeout > GetTime<std::chrono::milliseconds>());
44- UninterruptibleSleep (100ms);
45- }
52+ IndexWaitSynced (coin_stats_index);
4653
4754 // Check that CoinStatsIndex works for genesis block.
4855 const CBlockIndex* genesis_block_index;
@@ -78,4 +85,44 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
7885 // Rest of shutdown sequence and destructors happen in ~TestingSetup()
7986}
8087
88+ // Test shutdown between BlockConnected and ChainStateFlushed notifications,
89+ // make sure index is not corrupted and is able to reload.
90+ BOOST_FIXTURE_TEST_CASE (coinstatsindex_unclean_shutdown, TestChain100Setup)
91+ {
92+ CChainState& chainstate = Assert (m_node.chainman )->ActiveChainstate ();
93+ const CChainParams& params = Params ();
94+ {
95+ CoinStatsIndex index{1 << 20 };
96+ BOOST_REQUIRE (index.Start (chainstate));
97+ IndexWaitSynced (index);
98+ std::shared_ptr<const CBlock> new_block;
99+ CBlockIndex* new_block_index = nullptr ;
100+ {
101+ const CScript script_pub_key{CScript () << ToByteVector (coinbaseKey.GetPubKey ()) << OP_CHECKSIG};
102+ const CBlock block = this ->CreateBlock ({}, script_pub_key, chainstate);
103+
104+ new_block = std::make_shared<CBlock>(block);
105+
106+ LOCK (cs_main);
107+ BlockValidationState state;
108+ BOOST_CHECK (CheckBlock (block, state, params.GetConsensus ()));
109+ BOOST_CHECK (chainstate.AcceptBlock (new_block, state, &new_block_index, true , nullptr , nullptr ));
110+ CCoinsViewCache view (&chainstate.CoinsTip ());
111+ BOOST_CHECK (chainstate.ConnectBlock (block, state, new_block_index, view));
112+ }
113+ // Send block connected notification, then stop the index without
114+ // sending a chainstate flushed notification. Prior to #24138, this
115+ // would cause the index to be corrupted and fail to reload.
116+ ValidationInterfaceTest::BlockConnected (index, new_block, new_block_index);
117+ index.Stop ();
118+ }
119+
120+ {
121+ CoinStatsIndex index{1 << 20 };
122+ // Make sure the index can be loaded.
123+ BOOST_REQUIRE (index.Start (chainstate));
124+ index.Stop ();
125+ }
126+ }
127+
81128BOOST_AUTO_TEST_SUITE_END ()
0 commit comments