Skip to content

Commit 3c36139

Browse files
committed
test: add reset_chainstate parameter for snapshot unittests
This CreateAndActivateUTXOSnapshot parameter is necessary once we perform snapshot completion within ABC, since the existing UpdateTip test will fail because the IBD chain that has generated the snapshot will exceed the base of the snapshot. Being able to test snapshots being loaded into a mostly-uninitialized datadir allows for more realistic unittest scenarios.
1 parent 00b357c commit 3c36139

File tree

3 files changed

+52
-10
lines changed

3 files changed

+52
-10
lines changed

src/test/util/chainstate.h

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <node/context.h>
1212
#include <node/utxo_snapshot.h>
1313
#include <rpc/blockchain.h>
14+
#include <test/util/setup_common.h>
1415
#include <validation.h>
1516

1617
#include <univalue.h>
@@ -20,11 +21,20 @@ const auto NoMalleation = [](AutoFile& file, node::SnapshotMetadata& meta){};
2021
/**
2122
* Create and activate a UTXO snapshot, optionally providing a function to
2223
* malleate the snapshot.
24+
*
25+
* If `reset_chainstate` is true, reset the original chainstate back to the genesis
26+
* block. This allows us to simulate more realistic conditions in which a snapshot is
27+
* loaded into an otherwise mostly-uninitialized datadir. It also allows us to test
28+
* conditions that would otherwise cause shutdowns based on the IBD chainstate going
29+
* past the snapshot it generated.
2330
*/
2431
template<typename F = decltype(NoMalleation)>
2532
static bool
26-
CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F malleation = NoMalleation)
33+
CreateAndActivateUTXOSnapshot(TestingSetup* fixture, F malleation = NoMalleation, bool reset_chainstate = false)
2734
{
35+
node::NodeContext& node = fixture->m_node;
36+
fs::path root = fixture->m_path_root;
37+
2838
// Write out a snapshot to the test's tempdir.
2939
//
3040
int height;
@@ -47,6 +57,37 @@ CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F ma
4757

4858
malleation(auto_infile, metadata);
4959

60+
if (reset_chainstate) {
61+
{
62+
// What follows is code to selectively reset chainstate data without
63+
// disturbing the existing BlockManager instance, which is needed to
64+
// recognize the headers chain previously generated by the chainstate we're
65+
// removing. Without those headers, we can't activate the snapshot below.
66+
//
67+
// This is a stripped-down version of node::LoadChainstate which
68+
// preserves the block index.
69+
LOCK(::cs_main);
70+
uint256 gen_hash = node.chainman->ActiveChainstate().m_chain[0]->GetBlockHash();
71+
node.chainman->ResetChainstates();
72+
node.chainman->InitializeChainstate(node.mempool.get());
73+
Chainstate& chain = node.chainman->ActiveChainstate();
74+
Assert(chain.LoadGenesisBlock());
75+
// These cache values will be corrected shortly in `MaybeRebalanceCaches`.
76+
chain.InitCoinsDB(1 << 20, true, false, "");
77+
chain.InitCoinsCache(1 << 20);
78+
chain.CoinsTip().SetBestBlock(gen_hash);
79+
chain.setBlockIndexCandidates.insert(node.chainman->m_blockman.LookupBlockIndex(gen_hash));
80+
chain.LoadChainTip();
81+
node.chainman->MaybeRebalanceCaches();
82+
}
83+
BlockValidationState state;
84+
if (!node.chainman->ActiveChainstate().ActivateBestChain(state)) {
85+
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
86+
}
87+
Assert(
88+
0 == WITH_LOCK(node.chainman->GetMutex(), return node.chainman->ActiveHeight()));
89+
}
90+
5091
return node.chainman->ActivateSnapshot(auto_infile, metadata, /*in_memory=*/true);
5192
}
5293

src/test/validation_chainstate_tests.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
8989
// After adding some blocks to the tip, best block should have changed.
9090
BOOST_CHECK(::g_best_block != curr_tip);
9191

92-
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
92+
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(
93+
this, NoMalleation, /*reset_chainstate=*/ true));
9394

9495
// Ensure our active chain is the snapshot chainstate.
9596
BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.IsSnapshotActive()));

src/test/validation_chainstatemanager_tests.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ struct SnapshotTestSetup : TestChain100Setup {
185185
Chainstate& validation_chainstate = chainman.ActiveChainstate();
186186

187187
// Snapshot should refuse to load at this height.
188-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
188+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(this));
189189
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash);
190190
BOOST_CHECK(!chainman.SnapshotBlockhash());
191191

@@ -198,7 +198,7 @@ struct SnapshotTestSetup : TestChain100Setup {
198198

199199
// Should not load malleated snapshots
200200
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
201-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
201+
this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
202202
// A UTXO is missing but count is correct
203203
metadata.m_coins_count -= 1;
204204

@@ -209,27 +209,27 @@ struct SnapshotTestSetup : TestChain100Setup {
209209
auto_infile >> coin;
210210
}));
211211
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
212-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
212+
this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
213213
// Coins count is larger than coins in file
214214
metadata.m_coins_count += 1;
215215
}));
216216
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
217-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
217+
this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
218218
// Coins count is smaller than coins in file
219219
metadata.m_coins_count -= 1;
220220
}));
221221
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
222-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
222+
this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
223223
// Wrong hash
224224
metadata.m_base_blockhash = uint256::ZERO;
225225
}));
226226
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
227-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
227+
this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
228228
// Wrong hash
229229
metadata.m_base_blockhash = uint256::ONE;
230230
}));
231231

232-
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
232+
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(this));
233233

234234
// Ensure our active chain is the snapshot chainstate.
235235
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
@@ -320,7 +320,7 @@ struct SnapshotTestSetup : TestChain100Setup {
320320
}
321321

322322
// Snapshot should refuse to load after one has already loaded.
323-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
323+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(this));
324324

325325
// Snapshot blockhash should be unchanged.
326326
BOOST_CHECK_EQUAL(

0 commit comments

Comments
 (0)