mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 10:43:19 -03:00
test: add testcases for snapshot initialization
This commit is contained in:
parent
cced4e7336
commit
e4d7995286
1 changed files with 112 additions and 2 deletions
|
@ -10,6 +10,7 @@
|
|||
#include <sync.h>
|
||||
#include <test/util/chainstate.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <timedata.h>
|
||||
#include <uint256.h>
|
||||
#include <validation.h>
|
||||
#include <validationinterface.h>
|
||||
|
@ -155,12 +156,32 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
|
|||
}
|
||||
|
||||
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};
|
||||
|
@ -208,6 +229,9 @@ struct SnapshotTestSetup : TestChain100Setup {
|
|||
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
|
||||
|
@ -230,6 +254,7 @@ struct SnapshotTestSetup : TestChain100Setup {
|
|||
}));
|
||||
|
||||
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(this));
|
||||
BOOST_CHECK(fs::exists(*node::FindSnapshotChainstateDir()));
|
||||
|
||||
// Ensure our active chain is the snapshot chainstate.
|
||||
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
|
||||
|
@ -242,9 +267,11 @@ struct SnapshotTestSetup : TestChain100Setup {
|
|||
{
|
||||
LOCK(::cs_main);
|
||||
|
||||
fs::path found = *node::FindSnapshotChainstateDir();
|
||||
|
||||
// Note: WriteSnapshotBaseBlockhash() is implicitly tested above.
|
||||
BOOST_CHECK_EQUAL(
|
||||
*node::ReadSnapshotBaseBlockhash(m_args.GetDataDirNet() / "chainstate_snapshot"),
|
||||
*node::ReadSnapshotBaseBlockhash(found),
|
||||
*chainman.SnapshotBlockhash());
|
||||
|
||||
// Ensure that the genesis block was not marked assumed-valid.
|
||||
|
@ -328,6 +355,34 @@ struct SnapshotTestSetup : TestChain100Setup {
|
|||
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);
|
||||
const ChainstateManager::Options chainman_opts{
|
||||
.chainparams = ::Params(),
|
||||
.adjusted_time_callback = GetAdjustedTime,
|
||||
};
|
||||
// For robustness, ensure the old manager is destroyed before creating a
|
||||
// new one.
|
||||
m_node.chainman.reset();
|
||||
m_node.chainman.reset(new ChainstateManager(chainman_opts));
|
||||
}
|
||||
return *Assert(m_node.chainman);
|
||||
}
|
||||
};
|
||||
|
||||
//! Test basic snapshot activation.
|
||||
|
@ -414,4 +469,59 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
|
|||
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();
|
||||
|
||||
{
|
||||
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 (Chainstate* cs : chainman_restarted.GetAll()) {
|
||||
if (cs != &chainman_restarted.ActiveChainstate()) {
|
||||
BOOST_CHECK_EQUAL(cs->m_chain.Height(), 110);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Add table
Reference in a new issue