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