Skip to content

Commit 3a29dfb

Browse files
committed
move-only: test: make snapshot chainstate setup reusable
For use in next commit. Most easily reviewed with `--color-moved=dimmed_zebra --color-moved-ws=allow-indentation-change`.
1 parent 8153bd9 commit 3a29dfb

File tree

1 file changed

+151
-136
lines changed

1 file changed

+151
-136
lines changed

src/test/validation_chainstatemanager_tests.cpp

Lines changed: 151 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -154,171 +154,186 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
154154
BOOST_CHECK_CLOSE(c2.m_coinsdb_cache_size_bytes, max_cache * 0.95, 1);
155155
}
156156

157-
//! Test basic snapshot activation.
158-
BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
159-
{
160-
ChainstateManager& chainman = *Assert(m_node.chainman);
157+
struct SnapshotTestSetup : TestChain100Setup {
158+
std::tuple<Chainstate*, Chainstate*> SetupSnapshot()
159+
{
160+
ChainstateManager& chainman = *Assert(m_node.chainman);
161161

162-
size_t initial_size;
163-
size_t initial_total_coins{100};
162+
BOOST_CHECK(!chainman.IsSnapshotActive());
163+
WITH_LOCK(::cs_main, BOOST_CHECK(!chainman.IsSnapshotValidated()));
164164

165-
// Make some initial assertions about the contents of the chainstate.
166-
{
167-
LOCK(::cs_main);
168-
CCoinsViewCache& ibd_coinscache = chainman.ActiveChainstate().CoinsTip();
169-
initial_size = ibd_coinscache.GetCacheSize();
170-
size_t total_coins{0};
171-
172-
for (CTransactionRef& txn : m_coinbase_txns) {
173-
COutPoint op{txn->GetHash(), 0};
174-
BOOST_CHECK(ibd_coinscache.HaveCoin(op));
175-
total_coins++;
176-
}
165+
size_t initial_size;
166+
size_t initial_total_coins{100};
177167

178-
BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
179-
BOOST_CHECK_EQUAL(initial_size, initial_total_coins);
180-
}
168+
// Make some initial assertions about the contents of the chainstate.
169+
{
170+
LOCK(::cs_main);
171+
CCoinsViewCache& ibd_coinscache = chainman.ActiveChainstate().CoinsTip();
172+
initial_size = ibd_coinscache.GetCacheSize();
173+
size_t total_coins{0};
181174

182-
// Snapshot should refuse to load at this height.
183-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
184-
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash);
185-
BOOST_CHECK(!chainman.SnapshotBlockhash());
186-
187-
// Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can
188-
// be found.
189-
constexpr int snapshot_height = 110;
190-
mineBlocks(10);
191-
initial_size += 10;
192-
initial_total_coins += 10;
193-
194-
// Should not load malleated snapshots
195-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
196-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
197-
// A UTXO is missing but count is correct
198-
metadata.m_coins_count -= 1;
199-
200-
COutPoint outpoint;
201-
Coin coin;
202-
203-
auto_infile >> outpoint;
204-
auto_infile >> coin;
205-
}));
206-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
207-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
208-
// Coins count is larger than coins in file
209-
metadata.m_coins_count += 1;
210-
}));
211-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
212-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
213-
// Coins count is smaller than coins in file
214-
metadata.m_coins_count -= 1;
215-
}));
216-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
217-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
218-
// Wrong hash
219-
metadata.m_base_blockhash = uint256::ZERO;
220-
}));
221-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
222-
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
223-
// Wrong hash
224-
metadata.m_base_blockhash = uint256::ONE;
225-
}));
226-
227-
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
228-
229-
// Ensure our active chain is the snapshot chainstate.
230-
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
231-
BOOST_CHECK_EQUAL(
232-
*chainman.ActiveChainstate().m_from_snapshot_blockhash,
233-
*chainman.SnapshotBlockhash());
175+
for (CTransactionRef& txn : m_coinbase_txns) {
176+
COutPoint op{txn->GetHash(), 0};
177+
BOOST_CHECK(ibd_coinscache.HaveCoin(op));
178+
total_coins++;
179+
}
234180

235-
{
236-
LOCK(::cs_main);
181+
BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
182+
BOOST_CHECK_EQUAL(initial_size, initial_total_coins);
183+
}
237184

238-
// Note: WriteSnapshotBaseBlockhash() is implicitly tested above.
185+
Chainstate& validation_chainstate = chainman.ActiveChainstate();
186+
187+
// Snapshot should refuse to load at this height.
188+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
189+
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash);
190+
BOOST_CHECK(!chainman.SnapshotBlockhash());
191+
192+
// Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can
193+
// be found.
194+
constexpr int snapshot_height = 110;
195+
mineBlocks(10);
196+
initial_size += 10;
197+
initial_total_coins += 10;
198+
199+
// Should not load malleated snapshots
200+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
201+
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
202+
// A UTXO is missing but count is correct
203+
metadata.m_coins_count -= 1;
204+
205+
COutPoint outpoint;
206+
Coin coin;
207+
208+
auto_infile >> outpoint;
209+
auto_infile >> coin;
210+
}));
211+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
212+
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
213+
// Coins count is larger than coins in file
214+
metadata.m_coins_count += 1;
215+
}));
216+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
217+
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
218+
// Coins count is smaller than coins in file
219+
metadata.m_coins_count -= 1;
220+
}));
221+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
222+
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
223+
// Wrong hash
224+
metadata.m_base_blockhash = uint256::ZERO;
225+
}));
226+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
227+
m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
228+
// Wrong hash
229+
metadata.m_base_blockhash = uint256::ONE;
230+
}));
231+
232+
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
233+
234+
// Ensure our active chain is the snapshot chainstate.
235+
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
239236
BOOST_CHECK_EQUAL(
240-
*node::ReadSnapshotBaseBlockhash(m_args.GetDataDirNet() / "chainstate_snapshot"),
237+
*chainman.ActiveChainstate().m_from_snapshot_blockhash,
241238
*chainman.SnapshotBlockhash());
242239

243-
// Ensure that the genesis block was not marked assumed-valid.
244-
BOOST_CHECK(!chainman.ActiveChain().Genesis()->IsAssumedValid());
245-
}
240+
Chainstate& snapshot_chainstate = chainman.ActiveChainstate();
246241

247-
const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params());
248-
const CBlockIndex* tip = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());
242+
{
243+
LOCK(::cs_main);
249244

250-
BOOST_CHECK_EQUAL(tip->nChainTx, au_data.nChainTx);
245+
// Note: WriteSnapshotBaseBlockhash() is implicitly tested above.
246+
BOOST_CHECK_EQUAL(
247+
*node::ReadSnapshotBaseBlockhash(m_args.GetDataDirNet() / "chainstate_snapshot"),
248+
*chainman.SnapshotBlockhash());
251249

252-
// To be checked against later when we try loading a subsequent snapshot.
253-
uint256 loaded_snapshot_blockhash{*chainman.SnapshotBlockhash()};
250+
// Ensure that the genesis block was not marked assumed-valid.
251+
BOOST_CHECK(!chainman.ActiveChain().Genesis()->IsAssumedValid());
252+
}
254253

255-
// Make some assertions about the both chainstates. These checks ensure the
256-
// legacy chainstate hasn't changed and that the newly created chainstate
257-
// reflects the expected content.
258-
{
259-
LOCK(::cs_main);
260-
int chains_tested{0};
254+
const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params());
255+
const CBlockIndex* tip = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());
261256

262-
for (Chainstate* chainstate : chainman.GetAll()) {
263-
BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
264-
CCoinsViewCache& coinscache = chainstate->CoinsTip();
257+
BOOST_CHECK_EQUAL(tip->nChainTx, au_data.nChainTx);
265258

266-
// Both caches will be empty initially.
267-
BOOST_CHECK_EQUAL((unsigned int)0, coinscache.GetCacheSize());
259+
// To be checked against later when we try loading a subsequent snapshot.
260+
uint256 loaded_snapshot_blockhash{*chainman.SnapshotBlockhash()};
268261

269-
size_t total_coins{0};
262+
// Make some assertions about the both chainstates. These checks ensure the
263+
// legacy chainstate hasn't changed and that the newly created chainstate
264+
// reflects the expected content.
265+
{
266+
LOCK(::cs_main);
267+
int chains_tested{0};
270268

271-
for (CTransactionRef& txn : m_coinbase_txns) {
272-
COutPoint op{txn->GetHash(), 0};
273-
BOOST_CHECK(coinscache.HaveCoin(op));
274-
total_coins++;
275-
}
269+
for (Chainstate* chainstate : chainman.GetAll()) {
270+
BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
271+
CCoinsViewCache& coinscache = chainstate->CoinsTip();
276272

277-
BOOST_CHECK_EQUAL(initial_size , coinscache.GetCacheSize());
278-
BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
279-
chains_tested++;
280-
}
273+
// Both caches will be empty initially.
274+
BOOST_CHECK_EQUAL((unsigned int)0, coinscache.GetCacheSize());
281275

282-
BOOST_CHECK_EQUAL(chains_tested, 2);
283-
}
276+
size_t total_coins{0};
284277

285-
// Mine some new blocks on top of the activated snapshot chainstate.
286-
constexpr size_t new_coins{100};
287-
mineBlocks(new_coins); // Defined in TestChain100Setup.
278+
for (CTransactionRef& txn : m_coinbase_txns) {
279+
COutPoint op{txn->GetHash(), 0};
280+
BOOST_CHECK(coinscache.HaveCoin(op));
281+
total_coins++;
282+
}
288283

289-
{
290-
LOCK(::cs_main);
291-
size_t coins_in_active{0};
292-
size_t coins_in_background{0};
293-
size_t coins_missing_from_background{0};
284+
BOOST_CHECK_EQUAL(initial_size , coinscache.GetCacheSize());
285+
BOOST_CHECK_EQUAL(total_coins, initial_total_coins);
286+
chains_tested++;
287+
}
294288

295-
for (Chainstate* chainstate : chainman.GetAll()) {
296-
BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
297-
CCoinsViewCache& coinscache = chainstate->CoinsTip();
298-
bool is_background = chainstate != &chainman.ActiveChainstate();
289+
BOOST_CHECK_EQUAL(chains_tested, 2);
290+
}
299291

300-
for (CTransactionRef& txn : m_coinbase_txns) {
301-
COutPoint op{txn->GetHash(), 0};
302-
if (coinscache.HaveCoin(op)) {
303-
(is_background ? coins_in_background : coins_in_active)++;
304-
} else if (is_background) {
305-
coins_missing_from_background++;
292+
// Mine some new blocks on top of the activated snapshot chainstate.
293+
constexpr size_t new_coins{100};
294+
mineBlocks(new_coins); // Defined in TestChain100Setup.
295+
296+
{
297+
LOCK(::cs_main);
298+
size_t coins_in_active{0};
299+
size_t coins_in_background{0};
300+
size_t coins_missing_from_background{0};
301+
302+
for (Chainstate* chainstate : chainman.GetAll()) {
303+
BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString());
304+
CCoinsViewCache& coinscache = chainstate->CoinsTip();
305+
bool is_background = chainstate != &chainman.ActiveChainstate();
306+
307+
for (CTransactionRef& txn : m_coinbase_txns) {
308+
COutPoint op{txn->GetHash(), 0};
309+
if (coinscache.HaveCoin(op)) {
310+
(is_background ? coins_in_background : coins_in_active)++;
311+
} else if (is_background) {
312+
coins_missing_from_background++;
313+
}
306314
}
307315
}
316+
317+
BOOST_CHECK_EQUAL(coins_in_active, initial_total_coins + new_coins);
318+
BOOST_CHECK_EQUAL(coins_in_background, initial_total_coins);
319+
BOOST_CHECK_EQUAL(coins_missing_from_background, new_coins);
308320
}
309321

310-
BOOST_CHECK_EQUAL(coins_in_active, initial_total_coins + new_coins);
311-
BOOST_CHECK_EQUAL(coins_in_background, initial_total_coins);
312-
BOOST_CHECK_EQUAL(coins_missing_from_background, new_coins);
313-
}
322+
// Snapshot should refuse to load after one has already loaded.
323+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
314324

315-
// Snapshot should refuse to load after one has already loaded.
316-
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
325+
// Snapshot blockhash should be unchanged.
326+
BOOST_CHECK_EQUAL(
327+
*chainman.ActiveChainstate().m_from_snapshot_blockhash,
328+
loaded_snapshot_blockhash);
329+
return std::make_tuple(&validation_chainstate, &snapshot_chainstate);
330+
}
331+
};
317332

318-
// Snapshot blockhash should be unchanged.
319-
BOOST_CHECK_EQUAL(
320-
*chainman.ActiveChainstate().m_from_snapshot_blockhash,
321-
loaded_snapshot_blockhash);
333+
//! Test basic snapshot activation.
334+
BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, SnapshotTestSetup)
335+
{
336+
this->SetupSnapshot();
322337
}
323338

324339
//! Test LoadBlockIndex behavior when multiple chainstates are in use.

0 commit comments

Comments
 (0)