diff options
-rw-r--r-- | src/test/validation_chainstatemanager_tests.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index ca38f9d5fa..46aac7b2a3 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -312,4 +312,81 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup) loaded_snapshot_blockhash); } +//! Test LoadBlockIndex behavior when multiple chainstates are in use. +//! +//! - First, verfiy that setBlockIndexCandidates is as expected when using a single, +//! fully-validating chainstate. +//! +//! - Then mark a region of the chain BLOCK_ASSUMED_VALID and introduce a second chainstate +//! that will tolerate assumed-valid blocks. Run LoadBlockIndex() and ensure that the first +//! chainstate only contains fully validated blocks and the other chainstate contains all blocks, +//! even those assumed-valid. +//! +BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup) +{ + ChainstateManager& chainman = *Assert(m_node.chainman); + CTxMemPool& mempool = *m_node.mempool; + CChainState& cs1 = chainman.ActiveChainstate(); + + int num_indexes{0}; + int num_assumed_valid{0}; + const int expected_assumed_valid{20}; + const int last_assumed_valid_idx{40}; + const int assumed_valid_start_idx = last_assumed_valid_idx - expected_assumed_valid; + + CBlockIndex* validated_tip{nullptr}; + CBlockIndex* assumed_tip{chainman.ActiveChain().Tip()}; + + auto reload_all_block_indexes = [&]() { + for (CChainState* cs : chainman.GetAll()) { + LOCK(::cs_main); + cs->UnloadBlockIndex(); + BOOST_CHECK(cs->setBlockIndexCandidates.empty()); + } + + WITH_LOCK(::cs_main, chainman.LoadBlockIndex()); + }; + + // Ensure that without any assumed-valid BlockIndex entries, all entries are considered + // tip candidates. + reload_all_block_indexes(); + BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.size(), cs1.m_chain.Height() + 1); + + // Mark some region of the chain assumed-valid. + for (int i = 0; i <= cs1.m_chain.Height(); ++i) { + auto index = cs1.m_chain[i]; + + if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) { + index->nStatus = BlockStatus::BLOCK_VALID_TREE | BlockStatus::BLOCK_ASSUMED_VALID; + } + + ++num_indexes; + if (index->IsAssumedValid()) ++num_assumed_valid; + + // Note the last fully-validated block as the expected validated tip. + if (i == (assumed_valid_start_idx - 1)) { + validated_tip = index; + BOOST_CHECK(!index->IsAssumedValid()); + } + } + + BOOST_CHECK_EQUAL(expected_assumed_valid, num_assumed_valid); + + CChainState& cs2 = WITH_LOCK(::cs_main, + return chainman.InitializeChainstate(&mempool, GetRandHash())); + + reload_all_block_indexes(); + + // The fully validated chain only has candidates up to the start of the assumed-valid + // blocks. + BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.count(validated_tip), 1); + BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.count(assumed_tip), 0); + BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.size(), assumed_valid_start_idx); + + // The assumed-valid tolerant chain has all blocks as candidates. + BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(validated_tip), 1); + BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_tip), 1); + BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes); +} + BOOST_AUTO_TEST_SUITE_END() |