Page MenuHomePhabricator

D14655.id42717.diff
No OneTemporary

D14655.id42717.diff

diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -11,6 +11,7 @@
#include <sync.h>
#include <test/util/chainstate.h>
#include <test/util/setup_common.h>
+#include <timedata.h>
#include <validation.h>
#include <validationinterface.h>
@@ -170,11 +171,30 @@
}
struct SnapshotTestSetup : TestChain100Setup {
+ // Run with coinsdb on the filesystem to support, e.g., moving invalidated
+ // chainstate dirs to "*_invalid".
+ //
+ // Note that this means the tests run considerably slower than in-memory DB
+ // tests, but we can't otherwise test this functionality since it relies on
+ // destructive filesystem operations.
+ SnapshotTestSetup()
+ : TestChain100Setup{
+ {},
+ {},
+ /*coins_db_in_memory=*/false,
+ /*block_tree_db_in_memory=*/false,
+ } {}
+
std::tuple<Chainstate *, Chainstate *> SetupSnapshot() {
ChainstateManager &chainman = *Assert(m_node.chainman);
BOOST_CHECK(!chainman.IsSnapshotActive());
- WITH_LOCK(::cs_main, BOOST_CHECK(!chainman.IsSnapshotValidated()));
+
+ {
+ LOCK(::cs_main);
+ BOOST_CHECK(!chainman.IsSnapshotValidated());
+ BOOST_CHECK(!node::FindSnapshotChainstateDir());
+ }
size_t initial_size;
size_t initial_total_coins{100};
@@ -223,6 +243,9 @@
auto_infile >> outpoint;
auto_infile >> coin;
}));
+
+ BOOST_CHECK(!node::FindSnapshotChainstateDir());
+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
this, [](AutoFile &auto_infile, SnapshotMetadata &metadata) {
// Coins count is larger than coins in file
@@ -245,6 +268,7 @@
}));
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(this));
+ BOOST_CHECK(fs::exists(*node::FindSnapshotChainstateDir()));
// Ensure our active chain is the snapshot chainstate.
BOOST_CHECK(
@@ -258,18 +282,18 @@
{
LOCK(::cs_main);
+ fs::path found = *node::FindSnapshotChainstateDir();
+
// Note: WriteSnapshotBaseBlockhash() is implicitly tested above.
- BOOST_CHECK_EQUAL(
- *node::ReadSnapshotBaseBlockhash(m_args.GetDataDirNet() /
- "chainstate_snapshot"),
- *chainman.SnapshotBlockhash());
+ BOOST_CHECK_EQUAL(*node::ReadSnapshotBaseBlockhash(found),
+ *chainman.SnapshotBlockhash());
// Ensure that the genesis block was not marked assumed-valid.
BOOST_CHECK(!chainman.ActiveChain().Genesis()->IsAssumedValid());
}
- const AssumeutxoData &au_data =
- *ExpectedAssumeutxo(snapshot_height, ::Params());
+ const AssumeutxoData &au_data = *ExpectedAssumeutxo(
+ snapshot_height, ::GetConfig().GetChainParams());
const CBlockIndex *tip =
WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());
@@ -351,6 +375,29 @@
loaded_snapshot_blockhash);
return std::make_tuple(&validation_chainstate, &snapshot_chainstate);
}
+
+ // Simulate a restart of the node by flushing all state to disk, clearing
+ // the existing ChainstateManager, and unloading the block index.
+ //
+ // @returns a reference to the "restarted" ChainstateManager
+ ChainstateManager &SimulateNodeRestart() {
+ ChainstateManager &chainman = *Assert(m_node.chainman);
+
+ BOOST_TEST_MESSAGE("Simulating node restart");
+ {
+ LOCK(::cs_main);
+ for (Chainstate *cs : chainman.GetAll()) {
+ cs->ForceFlushStateToDisk();
+ }
+ chainman.ResetChainstates();
+ BOOST_CHECK_EQUAL(chainman.GetAll().size(), 0);
+ // For robustness, ensure the old manager is destroyed before
+ // creating a new one.
+ m_node.chainman.reset();
+ m_node.chainman.reset(new ChainstateManager(::GetConfig()));
+ }
+ return *Assert(m_node.chainman);
+ }
};
//! Test basic snapshot activation.
@@ -443,4 +490,61 @@
BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes);
}
+//! Ensure that snapshot chainstates initialize properly when found on disk.
+BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_init, SnapshotTestSetup) {
+ this->SetupSnapshot();
+
+ ChainstateManager &chainman = *Assert(m_node.chainman);
+
+ fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir();
+ BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
+ BOOST_CHECK_EQUAL(snapshot_chainstate_dir,
+ gArgs.GetDataDirNet() / "chainstate_snapshot");
+
+ BOOST_CHECK(chainman.IsSnapshotActive());
+ const uint256 snapshot_tip_hash = WITH_LOCK(
+ chainman.GetMutex(), return chainman.ActiveTip()->GetBlockHash());
+
+ auto all_chainstates = chainman.GetAll();
+ BOOST_CHECK_EQUAL(all_chainstates.size(), 2);
+
+ // Test that simulating a shutdown (resetting ChainstateManager) and then
+ // performing chainstate reinitializing successfully cleans up the
+ // background-validation chainstate data, and we end up with a single
+ // chainstate that is at tip.
+ ChainstateManager &chainman_restarted = this->SimulateNodeRestart();
+
+ BOOST_TEST_MESSAGE("Performing Load/Verify/Activate of chainstate");
+
+ // This call reinitializes the chainstates.
+ this->LoadVerifyActivateChainstate(::GetConfig());
+
+ {
+ LOCK(chainman_restarted.GetMutex());
+ BOOST_CHECK_EQUAL(chainman_restarted.GetAll().size(), 2);
+ BOOST_CHECK(chainman_restarted.IsSnapshotActive());
+ BOOST_CHECK(!chainman_restarted.IsSnapshotValidated());
+
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveTip()->GetBlockHash(),
+ snapshot_tip_hash);
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 210);
+ }
+
+ BOOST_TEST_MESSAGE("Ensure we can mine blocks on top of the initialized "
+ "snapshot chainstate");
+ mineBlocks(10);
+ {
+ LOCK(chainman_restarted.GetMutex());
+ BOOST_CHECK_EQUAL(chainman_restarted.ActiveHeight(), 220);
+
+ // Background chainstate should be unaware of new blocks on the snapshot
+ // chainstate.
+ for (const Chainstate *cs : chainman_restarted.GetAll()) {
+ if (cs != &chainman_restarted.ActiveChainstate()) {
+ BOOST_CHECK_EQUAL(cs->m_chain.Height(), 110);
+ }
+ }
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 26, 11:39 (16 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5573424
Default Alt Text
D14655.id42717.diff (6 KB)

Event Timeline