Skip to content

Commit 691d45f

Browse files
ryanofskymzumsande
authored andcommitted
Add coinstatsindex_unclean_shutdown test
1 parent eb6cc05 commit 691d45f

File tree

4 files changed

+69
-7
lines changed

4 files changed

+69
-7
lines changed

src/test/coinstatsindex_tests.cpp

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
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

1719
BOOST_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+
1932
BOOST_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+
81128
BOOST_AUTO_TEST_SUITE_END()

src/test/util/validation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <util/check.h>
88
#include <util/time.h>
99
#include <validation.h>
10+
#include <validationinterface.h>
1011

1112
void TestChainState::ResetIbd()
1213
{
@@ -20,3 +21,8 @@ void TestChainState::JumpOutOfIbd()
2021
m_cached_finished_ibd = true;
2122
Assert(!IsInitialBlockDownload());
2223
}
24+
25+
void ValidationInterfaceTest::BlockConnected(CValidationInterface& obj, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex)
26+
{
27+
obj.BlockConnected(block, pindex);
28+
}

src/test/util/validation.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,19 @@
77

88
#include <validation.h>
99

10+
class CValidationInterface;
11+
1012
struct TestChainState : public CChainState {
1113
/** Reset the ibd cache to its initial state */
1214
void ResetIbd();
1315
/** Toggle IsInitialBlockDownload from true to false */
1416
void JumpOutOfIbd();
1517
};
1618

19+
class ValidationInterfaceTest
20+
{
21+
public:
22+
static void BlockConnected(CValidationInterface& obj, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex);
23+
};
24+
1725
#endif // BITCOIN_TEST_UTIL_VALIDATION_H

src/validationinterface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ class CValidationInterface {
174174
* has been received and connected to the headers tree, though not validated yet */
175175
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
176176
friend class CMainSignals;
177+
friend class ValidationInterfaceTest;
177178
};
178179

179180
struct MainSignalsInstance;

0 commit comments

Comments
 (0)