Skip to content

Commit

Permalink
Add coinstatsindex_unclean_shutdown test
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanofsky authored and mzumsande committed Feb 25, 2022
1 parent eb6cc05 commit 691d45f
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 7 deletions.
61 changes: 54 additions & 7 deletions src/test/coinstatsindex_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <index/coinstatsindex.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
#include <util/time.h>
#include <validation.h>

Expand All @@ -16,6 +18,17 @@ using node::CoinStatsHashType;

BOOST_AUTO_TEST_SUITE(coinstatsindex_tests)

static void IndexWaitSynced(BaseIndex& index)
{
// Allow the CoinStatsIndex to catch up with the block index that is syncing
// in a background thread.
const auto timeout = GetTime<std::chrono::seconds>() + 120s;
while (!index.BlockUntilSyncedToCurrentChain()) {
BOOST_REQUIRE(timeout > GetTime<std::chrono::milliseconds>());
UninterruptibleSleep(100ms);
}
}

BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
{
CoinStatsIndex coin_stats_index{1 << 20, true};
Expand All @@ -36,13 +49,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)

BOOST_REQUIRE(coin_stats_index.Start(m_node.chainman->ActiveChainstate()));

// Allow the CoinStatsIndex to catch up with the block index that is syncing
// in a background thread.
const auto timeout = GetTime<std::chrono::seconds>() + 120s;
while (!coin_stats_index.BlockUntilSyncedToCurrentChain()) {
BOOST_REQUIRE(timeout > GetTime<std::chrono::milliseconds>());
UninterruptibleSleep(100ms);
}
IndexWaitSynced(coin_stats_index);

// Check that CoinStatsIndex works for genesis block.
const CBlockIndex* genesis_block_index;
Expand Down Expand Up @@ -78,4 +85,44 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
// Rest of shutdown sequence and destructors happen in ~TestingSetup()
}

// Test shutdown between BlockConnected and ChainStateFlushed notifications,
// make sure index is not corrupted and is able to reload.
BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
{
CChainState& chainstate = Assert(m_node.chainman)->ActiveChainstate();
const CChainParams& params = Params();
{
CoinStatsIndex index{1 << 20};
BOOST_REQUIRE(index.Start(chainstate));
IndexWaitSynced(index);
std::shared_ptr<const CBlock> new_block;
CBlockIndex* new_block_index = nullptr;
{
const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};
const CBlock block = this->CreateBlock({}, script_pub_key, chainstate);

new_block = std::make_shared<CBlock>(block);

LOCK(cs_main);
BlockValidationState state;
BOOST_CHECK(CheckBlock(block, state, params.GetConsensus()));
BOOST_CHECK(chainstate.AcceptBlock(new_block, state, &new_block_index, true, nullptr, nullptr));
CCoinsViewCache view(&chainstate.CoinsTip());
BOOST_CHECK(chainstate.ConnectBlock(block, state, new_block_index, view));
}
// Send block connected notification, then stop the index without
// sending a chainstate flushed notification. Prior to #24138, this
// would cause the index to be corrupted and fail to reload.
ValidationInterfaceTest::BlockConnected(index, new_block, new_block_index);
index.Stop();
}

{
CoinStatsIndex index{1 << 20};
// Make sure the index can be loaded.
BOOST_REQUIRE(index.Start(chainstate));
index.Stop();
}
}

BOOST_AUTO_TEST_SUITE_END()
6 changes: 6 additions & 0 deletions src/test/util/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <util/check.h>
#include <util/time.h>
#include <validation.h>
#include <validationinterface.h>

void TestChainState::ResetIbd()
{
Expand All @@ -20,3 +21,8 @@ void TestChainState::JumpOutOfIbd()
m_cached_finished_ibd = true;
Assert(!IsInitialBlockDownload());
}

void ValidationInterfaceTest::BlockConnected(CValidationInterface& obj, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex)
{
obj.BlockConnected(block, pindex);
}
8 changes: 8 additions & 0 deletions src/test/util/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@

#include <validation.h>

class CValidationInterface;

struct TestChainState : public CChainState {
/** Reset the ibd cache to its initial state */
void ResetIbd();
/** Toggle IsInitialBlockDownload from true to false */
void JumpOutOfIbd();
};

class ValidationInterfaceTest
{
public:
static void BlockConnected(CValidationInterface& obj, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex);
};

#endif // BITCOIN_TEST_UTIL_VALIDATION_H
1 change: 1 addition & 0 deletions src/validationinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class CValidationInterface {
* has been received and connected to the headers tree, though not validated yet */
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
friend class CMainSignals;
friend class ValidationInterfaceTest;
};

struct MainSignalsInstance;
Expand Down

0 comments on commit 691d45f

Please sign in to comment.