Branch data Line data Source code
1 : : // Copyright (c) 2020-2022 The Bitcoin Core developers 2 : : // Distributed under the MIT software license, see the accompanying 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : : // 5 : : #include <chainparams.h> 6 : : #include <consensus/validation.h> 7 : : #include <random.h> 8 : : #include <rpc/blockchain.h> 9 : : #include <sync.h> 10 : : #include <test/util/chainstate.h> 11 : : #include <test/util/coins.h> 12 : : #include <test/util/random.h> 13 : : #include <test/util/setup_common.h> 14 : : #include <uint256.h> 15 : : #include <validation.h> 16 : : 17 : 0 : #include <vector> 18 : 0 : 19 : : #include <boost/test/unit_test.hpp> 20 : : 21 : 0 : BOOST_FIXTURE_TEST_SUITE(validation_chainstate_tests, ChainTestingSetup) 22 : : 23 : : //! Test resizing coins-related Chainstate caches during runtime. 24 : : //! 25 : 0 : BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) 26 : : { 27 : 0 : ChainstateManager& manager = *Assert(m_node.chainman); 28 : 0 : CTxMemPool& mempool = *Assert(m_node.mempool); 29 : 0 : Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool)); 30 : 0 : c1.InitCoinsDB( 31 : : /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); 32 : 0 : WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23)); 33 : 0 : BOOST_REQUIRE(c1.LoadGenesisBlock()); // Need at least one block loaded to be able to flush caches 34 : : 35 : : // Add a coin to the in-memory cache, upsize once, then downsize. 36 : : { 37 : 0 : LOCK(::cs_main); 38 : 0 : const auto outpoint = AddTestCoin(c1.CoinsTip()); 39 : : 40 : : // Set a meaningless bestblock value in the coinsview cache - otherwise we won't 41 : : // flush during ResizecoinsCaches() and will subsequently hit an assertion. 42 : 0 : c1.CoinsTip().SetBestBlock(InsecureRand256()); 43 : : 44 : 0 : BOOST_CHECK(c1.CoinsTip().HaveCoinInCache(outpoint)); 45 : : 46 : 0 : c1.ResizeCoinsCaches( 47 : : 1 << 24, // upsizing the coinsview cache 48 : : 1 << 22 // downsizing the coinsdb cache 49 : : ); 50 : : 51 : 0 : // View should still have the coin cached, since we haven't destructed the cache on upsize. 52 : 0 : BOOST_CHECK(c1.CoinsTip().HaveCoinInCache(outpoint)); 53 : : 54 : 0 : c1.ResizeCoinsCaches( 55 : : 1 << 22, // downsizing the coinsview cache 56 : : 1 << 23 // upsizing the coinsdb cache 57 : : ); 58 : : 59 : : // The view cache should be empty since we had to destruct to downsize. 60 : 0 : BOOST_CHECK(!c1.CoinsTip().HaveCoinInCache(outpoint)); 61 : 0 : } 62 : 0 : } 63 : : 64 : : //! Test UpdateTip behavior for both active and background chainstates. 65 : : //! 66 : : //! When run on the background chainstate, UpdateTip should do a subset 67 : : //! of what it does for the active chainstate. 68 : 0 : BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup) 69 : : { 70 : 0 : ChainstateManager& chainman = *Assert(m_node.chainman); 71 : 0 : uint256 curr_tip = ::g_best_block; 72 : : 73 : : // Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can 74 : 0 : // be found. 75 : 0 : mineBlocks(10); 76 : : 77 : : // After adding some blocks to the tip, best block should have changed. 78 : 0 : BOOST_CHECK(::g_best_block != curr_tip); 79 : : 80 : : // Grab block 1 from disk; we'll add it to the background chain later. 81 : 0 : std::shared_ptr<CBlock> pblockone = std::make_shared<CBlock>(); 82 : : { 83 : 0 : LOCK(::cs_main); 84 : 0 : chainman.m_blockman.ReadBlockFromDisk(*pblockone, *chainman.ActiveChain()[1]); 85 : 0 : } 86 : : 87 : 0 : BOOST_REQUIRE(CreateAndActivateUTXOSnapshot( 88 : : this, NoMalleation, /*reset_chainstate=*/ true)); 89 : : 90 : : // Ensure our active chain is the snapshot chainstate. 91 : 0 : BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.IsSnapshotActive())); 92 : : 93 : 0 : curr_tip = ::g_best_block; 94 : : 95 : : // Mine a new block on top of the activated snapshot chainstate. 96 : 0 : mineBlocks(1); // Defined in TestChain100Setup. 97 : : 98 : : // After adding some blocks to the snapshot tip, best block should have changed. 99 : 0 : BOOST_CHECK(::g_best_block != curr_tip); 100 : : 101 : 0 : curr_tip = ::g_best_block; 102 : : 103 : 0 : BOOST_CHECK_EQUAL(chainman.GetAll().size(), 2); 104 : : 105 : 0 : Chainstate& background_cs{*[&] { 106 : 0 : for (Chainstate* cs : chainman.GetAll()) { 107 : 0 : if (cs != &chainman.ActiveChainstate()) { 108 : 0 : return cs; 109 : : } 110 : : } 111 : 0 : assert(false); 112 : 0 : }()}; 113 : : 114 : : // Append the first block to the background chain. 115 : 0 : BlockValidationState state; 116 : 0 : CBlockIndex* pindex = nullptr; 117 : 0 : const CChainParams& chainparams = Params(); 118 : 0 : bool newblock = false; 119 : : 120 : : // TODO: much of this is inlined from ProcessNewBlock(); just reuse PNB() 121 : : // once it is changed to support multiple chainstates. 122 : : { 123 : 0 : LOCK(::cs_main); 124 : 0 : bool checked = CheckBlock(*pblockone, state, chainparams.GetConsensus()); 125 : 0 : BOOST_CHECK(checked); 126 : 0 : bool accepted = chainman.AcceptBlock( 127 : 0 : pblockone, state, &pindex, true, nullptr, &newblock, true); 128 : 0 : BOOST_CHECK(accepted); 129 : 0 : } 130 : : 131 : : // UpdateTip is called here 132 : 0 : bool block_added = background_cs.ActivateBestChain(state, pblockone); 133 : : 134 : : // Ensure tip is as expected 135 : 0 : BOOST_CHECK_EQUAL(background_cs.m_chain.Tip()->GetBlockHash(), pblockone->GetHash()); 136 : : 137 : : // g_best_block should be unchanged after adding a block to the background 138 : : // validation chain. 139 : 0 : BOOST_CHECK(block_added); 140 : 0 : BOOST_CHECK_EQUAL(curr_tip, ::g_best_block); 141 : 0 : } 142 : : 143 : 0 : BOOST_AUTO_TEST_SUITE_END()