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