aboutsummaryrefslogtreecommitdiff
path: root/src/test/validation_chainstatemanager_tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/validation_chainstatemanager_tests.cpp')
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp121
1 files changed, 82 insertions, 39 deletions
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 9e359eeee4..227d7d4633 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -4,6 +4,7 @@
//
#include <chainparams.h>
#include <consensus/validation.h>
+#include <kernel/disconnected_transactions.h>
#include <node/kernel_notifications.h>
#include <node/utxo_snapshot.h>
#include <random.h>
@@ -29,30 +30,22 @@ using node::BlockManager;
using node::KernelNotifications;
using node::SnapshotMetadata;
-BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, ChainTestingSetup)
+BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, TestingSetup)
//! Basic tests for ChainstateManager.
//!
//! First create a legacy (IBD) chainstate, then create a snapshot chainstate.
-BOOST_AUTO_TEST_CASE(chainstatemanager)
+BOOST_FIXTURE_TEST_CASE(chainstatemanager, TestChain100Setup)
{
ChainstateManager& manager = *m_node.chainman;
- CTxMemPool& mempool = *m_node.mempool;
-
std::vector<Chainstate*> chainstates;
BOOST_CHECK(!manager.SnapshotBlockhash().has_value());
// Create a legacy (IBD) chainstate.
//
- Chainstate& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(&mempool));
+ Chainstate& c1 = manager.ActiveChainstate();
chainstates.push_back(&c1);
- c1.InitCoinsDB(
- /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
- WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
- c1.LoadGenesisBlock();
- BlockValidationState val_state;
- BOOST_CHECK(c1.ActivateBestChain(val_state, nullptr));
BOOST_CHECK(!manager.IsSnapshotActive());
BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
@@ -62,8 +55,9 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
auto& active_chain = WITH_LOCK(manager.GetMutex(), return manager.ActiveChain());
BOOST_CHECK_EQUAL(&active_chain, &c1.m_chain);
- BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 0);
-
+ // Get to a valid assumeutxo tip (per chainparams);
+ mineBlocks(10);
+ BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 110);
auto active_tip = WITH_LOCK(manager.GetMutex(), return manager.ActiveTip());
auto exp_tip = c1.m_chain.Tip();
BOOST_CHECK_EQUAL(active_tip, exp_tip);
@@ -73,19 +67,21 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
// Create a snapshot-based chainstate.
//
const uint256 snapshot_blockhash = active_tip->GetBlockHash();
- Chainstate& c2 = WITH_LOCK(::cs_main, return manager.ActivateExistingSnapshot(
- &mempool, snapshot_blockhash));
+ Chainstate& c2 = WITH_LOCK(::cs_main, return manager.ActivateExistingSnapshot(snapshot_blockhash));
chainstates.push_back(&c2);
-
- BOOST_CHECK_EQUAL(manager.SnapshotBlockhash().value(), snapshot_blockhash);
-
c2.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
- WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23));
- c2.m_chain.SetTip(*active_tip);
+ {
+ LOCK(::cs_main);
+ c2.InitCoinsCache(1 << 23);
+ c2.CoinsTip().SetBestBlock(active_tip->GetBlockHash());
+ c2.setBlockIndexCandidates.insert(manager.m_blockman.LookupBlockIndex(active_tip->GetBlockHash()));
+ c2.LoadChainTip();
+ }
BlockValidationState _;
BOOST_CHECK(c2.ActivateBestChain(_, nullptr));
+ BOOST_CHECK_EQUAL(manager.SnapshotBlockhash().value(), snapshot_blockhash);
BOOST_CHECK(manager.IsSnapshotActive());
BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
BOOST_CHECK_EQUAL(&c2, &manager.ActiveChainstate());
@@ -96,13 +92,15 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
auto& active_chain2 = WITH_LOCK(manager.GetMutex(), return manager.ActiveChain());
BOOST_CHECK_EQUAL(&active_chain2, &c2.m_chain);
- BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 0);
+ BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 110);
+ mineBlocks(1);
+ BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 111);
+ BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return c1.m_chain.Height()), 110);
auto active_tip2 = WITH_LOCK(manager.GetMutex(), return manager.ActiveTip());
- auto exp_tip2 = c2.m_chain.Tip();
- BOOST_CHECK_EQUAL(active_tip2, exp_tip2);
-
- BOOST_CHECK_EQUAL(exp_tip, exp_tip2);
+ BOOST_CHECK_EQUAL(active_tip, active_tip2->pprev);
+ BOOST_CHECK_EQUAL(active_tip, c1.m_chain.Tip());
+ BOOST_CHECK_EQUAL(active_tip2, c2.m_chain.Tip());
// Let scheduler events finish running to avoid accessing memory that is going to be unloaded
SyncWithValidationInterfaceQueue();
@@ -112,7 +110,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
BOOST_FIXTURE_TEST_CASE(chainstatemanager_rebalance_caches, TestChain100Setup)
{
ChainstateManager& manager = *m_node.chainman;
- CTxMemPool& mempool = *m_node.mempool;
size_t max_cache = 10000;
manager.m_total_coinsdb_cache = max_cache;
@@ -124,9 +121,6 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_rebalance_caches, TestChain100Setup)
//
Chainstate& c1 = manager.ActiveChainstate();
chainstates.push_back(&c1);
- c1.InitCoinsDB(
- /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
-
{
LOCK(::cs_main);
c1.InitCoinsCache(1 << 23);
@@ -139,7 +133,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_rebalance_caches, TestChain100Setup)
// Create a snapshot-based chainstate.
//
CBlockIndex* snapshot_base{WITH_LOCK(manager.GetMutex(), return manager.ActiveChain()[manager.ActiveChain().Height() / 2])};
- Chainstate& c2 = WITH_LOCK(cs_main, return manager.ActivateExistingSnapshot(&mempool, *snapshot_base->phashBlock));
+ Chainstate& c2 = WITH_LOCK(cs_main, return manager.ActivateExistingSnapshot(*snapshot_base->phashBlock));
chainstates.push_back(&c2);
c2.InitCoinsDB(
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
@@ -288,10 +282,10 @@ struct SnapshotTestSetup : TestChain100Setup {
BOOST_CHECK(!chainman.ActiveChain().Genesis()->IsAssumedValid());
}
- const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params());
+ const auto& au_data = ::Params().AssumeutxoForHeight(snapshot_height);
const CBlockIndex* tip = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());
- BOOST_CHECK_EQUAL(tip->nChainTx, au_data.nChainTx);
+ BOOST_CHECK_EQUAL(tip->nChainTx, au_data->nChainTx);
// To be checked against later when we try loading a subsequent snapshot.
uint256 loaded_snapshot_blockhash{*chainman.SnapshotBlockhash()};
@@ -425,18 +419,24 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, SnapshotTestSetup)
BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
{
ChainstateManager& chainman = *Assert(m_node.chainman);
- CTxMemPool& mempool = *m_node.mempool;
Chainstate& cs1 = chainman.ActiveChainstate();
int num_indexes{0};
int num_assumed_valid{0};
+ // Blocks in range [assumed_valid_start_idx, last_assumed_valid_idx) will be
+ // marked as assumed-valid and not having data.
const int expected_assumed_valid{20};
- const int last_assumed_valid_idx{40};
+ const int last_assumed_valid_idx{111};
const int assumed_valid_start_idx = last_assumed_valid_idx - expected_assumed_valid;
+ // Mine to height 120, past the hardcoded regtest assumeutxo snapshot at
+ // height 110
+ mineBlocks(20);
+
CBlockIndex* validated_tip{nullptr};
CBlockIndex* assumed_base{nullptr};
CBlockIndex* assumed_tip{WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip())};
+ BOOST_CHECK_EQUAL(assumed_tip->nHeight, 120);
auto reload_all_block_indexes = [&]() {
// For completeness, we also reset the block sequence counters to
@@ -462,7 +462,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
LOCK(::cs_main);
auto index = cs1.m_chain[i];
- // Blocks with heights in range [20, 40) are marked ASSUMED_VALID
+ // Blocks with heights in range [91, 110] are marked ASSUMED_VALID
if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) {
index->nStatus = BlockStatus::BLOCK_VALID_TREE | BlockStatus::BLOCK_ASSUMED_VALID;
}
@@ -488,7 +488,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
// Note: cs2's tip is not set when ActivateExistingSnapshot is called.
Chainstate& cs2 = WITH_LOCK(::cs_main,
- return chainman.ActivateExistingSnapshot(&mempool, *assumed_base->phashBlock));
+ return chainman.ActivateExistingSnapshot(*assumed_base->phashBlock));
// Set tip of the fully validated chain to be the validated tip
cs1.m_chain.SetTip(*validated_tip);
@@ -496,10 +496,36 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
// Set tip of the assume-valid-based chain to the assume-valid block
cs2.m_chain.SetTip(*assumed_base);
+ // Sanity check test variables.
+ BOOST_CHECK_EQUAL(num_indexes, 121); // 121 total blocks, including genesis
+ BOOST_CHECK_EQUAL(assumed_tip->nHeight, 120); // original chain has height 120
+ BOOST_CHECK_EQUAL(validated_tip->nHeight, 90); // current cs1 chain has height 90
+ BOOST_CHECK_EQUAL(assumed_base->nHeight, 110); // current cs2 chain has height 110
+
+ // Regenerate cs1.setBlockIndexCandidates and cs2.setBlockIndexCandidate and
+ // check contents below.
reload_all_block_indexes();
- // The fully validated chain should have the current validated tip
- // and the assumed valid base as candidates.
+ // The fully validated chain should only have the current validated tip and
+ // the assumed valid base as candidates, blocks 90 and 110. Specifically:
+ //
+ // - It does not have blocks 0-89 because they contain less work than the
+ // chain tip.
+ //
+ // - It has block 90 because it has data and equal work to the chain tip,
+ // (since it is the chain tip).
+ //
+ // - It does not have blocks 91-109 because they do not contain data.
+ //
+ // - It has block 110 even though it does not have data, because
+ // LoadBlockIndex has a special case to always add the snapshot block as a
+ // candidate. The special case is only actually intended to apply to the
+ // snapshot chainstate cs2, not the background chainstate cs1, but it is
+ // written broadly and applies to both.
+ //
+ // - It does not have any blocks after height 110 because cs1 is a background
+ // chainstate, and only blocks where are ancestors of the snapshot block
+ // are added as candidates for the background chainstate.
BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.size(), 2);
BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.count(validated_tip), 1);
BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.count(assumed_base), 1);
@@ -507,8 +533,25 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
// The assumed-valid tolerant chain has the assumed valid base as a
// candidate, but otherwise has none of the assumed-valid (which do not
// HAVE_DATA) blocks as candidates.
+ //
+ // Specifically:
+ // - All blocks below height 110 are not candidates, because cs2 chain tip
+ // has height 110 and they have less work than it does.
+ //
+ // - Block 110 is a candidate even though it does not have data, because it
+ // is the snapshot block, which is assumed valid.
+ //
+ // - Blocks 111-120 are added because they have data.
+
+ // Check that block 90 is absent
BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(validated_tip), 0);
+ // Check that block 109 is absent
+ BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_base->pprev), 0);
+ // Check that block 110 is present
+ BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_base), 1);
+ // Check that block 120 is present
BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_tip), 1);
+ // Check that 11 blocks total are present.
BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes - last_assumed_valid_idx + 1);
}
@@ -536,7 +579,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_init, SnapshotTestSetup)
// it will initialize instead of attempting to complete validation.
//
// Note that this is not a realistic use of DisconnectTip().
- DisconnectedBlockTransactions unused_pool;
+ DisconnectedBlockTransactions unused_pool{MAX_DISCONNECTED_TX_POOL_SIZE * 1000};
BlockValidationState unused_state;
{
LOCK2(::cs_main, bg_chainstate.MempoolMutex());