aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/test/coinstatsindex_tests.cpp61
-rw-r--r--src/test/util/validation.cpp6
-rw-r--r--src/test/util/validation.h8
-rw-r--r--src/validationinterface.h1
4 files changed, 69 insertions, 7 deletions
diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp
index 92de4ec7ba..5b73481bc1 100644
--- a/src/test/coinstatsindex_tests.cpp
+++ b/src/test/coinstatsindex_tests.cpp
@@ -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>
@@ -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};
@@ -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;
@@ -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()
diff --git a/src/test/util/validation.cpp b/src/test/util/validation.cpp
index 1aed492c3c..49535855f9 100644
--- a/src/test/util/validation.cpp
+++ b/src/test/util/validation.cpp
@@ -7,6 +7,7 @@
#include <util/check.h>
#include <util/time.h>
#include <validation.h>
+#include <validationinterface.h>
void TestChainState::ResetIbd()
{
@@ -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);
+}
diff --git a/src/test/util/validation.h b/src/test/util/validation.h
index b13aa0be60..b0bc717b6c 100644
--- a/src/test/util/validation.h
+++ b/src/test/util/validation.h
@@ -7,6 +7,8 @@
#include <validation.h>
+class CValidationInterface;
+
struct TestChainState : public CChainState {
/** Reset the ibd cache to its initial state */
void ResetIbd();
@@ -14,4 +16,10 @@ struct TestChainState : public CChainState {
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
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 7c3ce00fbc..ac62f8b467 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -174,6 +174,7 @@ protected:
* 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;