LCOV - code coverage report
Current view: top level - src/test - blockfilter_index_tests.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 198 206 96.1 %
Date: 2022-04-21 14:51:19 Functions: 6 6 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 27 30 90.0 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2017-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 <blockfilter.h>
#       6                 :            : #include <chainparams.h>
#       7                 :            : #include <consensus/merkle.h>
#       8                 :            : #include <consensus/validation.h>
#       9                 :            : #include <index/blockfilterindex.h>
#      10                 :            : #include <node/miner.h>
#      11                 :            : #include <pow.h>
#      12                 :            : #include <script/standard.h>
#      13                 :            : #include <test/util/blockfilter.h>
#      14                 :            : #include <test/util/setup_common.h>
#      15                 :            : #include <util/time.h>
#      16                 :            : #include <validation.h>
#      17                 :            : 
#      18                 :            : #include <boost/test/unit_test.hpp>
#      19                 :            : 
#      20                 :            : using node::BlockAssembler;
#      21                 :            : using node::CBlockTemplate;
#      22                 :            : 
#      23                 :            : BOOST_AUTO_TEST_SUITE(blockfilter_index_tests)
#      24                 :            : 
#      25                 :            : struct BuildChainTestingSetup : public TestChain100Setup {
#      26                 :            :     CBlock CreateBlock(const CBlockIndex* prev, const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey);
#      27                 :            :     bool BuildChain(const CBlockIndex* pindex, const CScript& coinbase_script_pub_key, size_t length, std::vector<std::shared_ptr<CBlock>>& chain);
#      28                 :            : };
#      29                 :            : 
#      30                 :            : static bool CheckFilterLookups(BlockFilterIndex& filter_index, const CBlockIndex* block_index,
#      31                 :            :                                uint256& last_header)
#      32                 :        228 : {
#      33                 :        228 :     BlockFilter expected_filter;
#      34         [ -  + ]:        228 :     if (!ComputeFilter(filter_index.GetFilterType(), block_index, expected_filter)) {
#      35                 :          0 :         BOOST_ERROR("ComputeFilter failed on block " << block_index->nHeight);
#      36                 :          0 :         return false;
#      37                 :          0 :     }
#      38                 :            : 
#      39                 :        228 :     BlockFilter filter;
#      40                 :        228 :     uint256 filter_header;
#      41                 :        228 :     std::vector<BlockFilter> filters;
#      42                 :        228 :     std::vector<uint256> filter_hashes;
#      43                 :            : 
#      44                 :        228 :     BOOST_CHECK(filter_index.LookupFilter(block_index, filter));
#      45                 :        228 :     BOOST_CHECK(filter_index.LookupFilterHeader(block_index, filter_header));
#      46                 :        228 :     BOOST_CHECK(filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
#      47                 :        228 :     BOOST_CHECK(filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
#      48                 :        228 :                                                    filter_hashes));
#      49                 :            : 
#      50                 :        228 :     BOOST_CHECK_EQUAL(filters.size(), 1U);
#      51                 :        228 :     BOOST_CHECK_EQUAL(filter_hashes.size(), 1U);
#      52                 :            : 
#      53                 :        228 :     BOOST_CHECK_EQUAL(filter.GetHash(), expected_filter.GetHash());
#      54                 :        228 :     BOOST_CHECK_EQUAL(filter_header, expected_filter.ComputeHeader(last_header));
#      55                 :        228 :     BOOST_CHECK_EQUAL(filters[0].GetHash(), expected_filter.GetHash());
#      56                 :        228 :     BOOST_CHECK_EQUAL(filter_hashes[0], expected_filter.GetHash());
#      57                 :            : 
#      58                 :        228 :     filters.clear();
#      59                 :        228 :     filter_hashes.clear();
#      60                 :        228 :     last_header = filter_header;
#      61                 :        228 :     return true;
#      62                 :        228 : }
#      63                 :            : 
#      64                 :            : CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev,
#      65                 :            :     const std::vector<CMutableTransaction>& txns,
#      66                 :            :     const CScript& scriptPubKey)
#      67                 :         40 : {
#      68                 :         40 :     const CChainParams& chainparams = Params();
#      69                 :         40 :     std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(m_node.chainman->ActiveChainstate(), *m_node.mempool, chainparams).CreateNewBlock(scriptPubKey);
#      70                 :         40 :     CBlock& block = pblocktemplate->block;
#      71                 :         40 :     block.hashPrevBlock = prev->GetBlockHash();
#      72                 :         40 :     block.nTime = prev->nTime + 1;
#      73                 :            : 
#      74                 :            :     // Replace mempool-selected txns with just coinbase plus passed-in txns:
#      75                 :         40 :     block.vtx.resize(1);
#      76         [ -  + ]:         40 :     for (const CMutableTransaction& tx : txns) {
#      77                 :          0 :         block.vtx.push_back(MakeTransactionRef(tx));
#      78                 :          0 :     }
#      79                 :         40 :     {
#      80                 :         40 :         CMutableTransaction tx_coinbase{*block.vtx.at(0)};
#      81                 :         40 :         tx_coinbase.vin.at(0).scriptSig = CScript{} << prev->nHeight + 1;
#      82                 :         40 :         block.vtx.at(0) = MakeTransactionRef(std::move(tx_coinbase));
#      83                 :         40 :         block.hashMerkleRoot = BlockMerkleRoot(block);
#      84                 :         40 :     }
#      85                 :            : 
#      86         [ +  + ]:         88 :     while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
#      87                 :            : 
#      88                 :         40 :     return block;
#      89                 :         40 : }
#      90                 :            : 
#      91                 :            : bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
#      92                 :            :     const CScript& coinbase_script_pub_key,
#      93                 :            :     size_t length,
#      94                 :            :     std::vector<std::shared_ptr<CBlock>>& chain)
#      95                 :          4 : {
#      96                 :          4 :     std::vector<CMutableTransaction> no_txns;
#      97                 :            : 
#      98                 :          4 :     chain.resize(length);
#      99         [ +  + ]:         40 :     for (auto& block : chain) {
#     100                 :         40 :         block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
#     101                 :         40 :         CBlockHeader header = block->GetBlockHeader();
#     102                 :            : 
#     103                 :         40 :         BlockValidationState state;
#     104         [ -  + ]:         40 :         if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex)) {
#     105                 :          0 :             return false;
#     106                 :          0 :         }
#     107                 :         40 :     }
#     108                 :            : 
#     109                 :          4 :     return true;
#     110                 :          4 : }
#     111                 :            : 
#     112                 :            : BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
#     113                 :          2 : {
#     114                 :          2 :     BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true);
#     115                 :            : 
#     116                 :          2 :     uint256 last_header;
#     117                 :            : 
#     118                 :            :     // Filter should not be found in the index before it is started.
#     119                 :          2 :     {
#     120                 :          2 :         LOCK(cs_main);
#     121                 :            : 
#     122                 :          2 :         BlockFilter filter;
#     123                 :          2 :         uint256 filter_header;
#     124                 :          2 :         std::vector<BlockFilter> filters;
#     125                 :          2 :         std::vector<uint256> filter_hashes;
#     126                 :            : 
#     127                 :          2 :         for (const CBlockIndex* block_index = m_node.chainman->ActiveChain().Genesis();
#     128         [ +  + ]:        204 :              block_index != nullptr;
#     129                 :        202 :              block_index = m_node.chainman->ActiveChain().Next(block_index)) {
#     130                 :        202 :             BOOST_CHECK(!filter_index.LookupFilter(block_index, filter));
#     131                 :        202 :             BOOST_CHECK(!filter_index.LookupFilterHeader(block_index, filter_header));
#     132                 :        202 :             BOOST_CHECK(!filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
#     133                 :        202 :             BOOST_CHECK(!filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
#     134                 :        202 :                                                             filter_hashes));
#     135                 :        202 :         }
#     136                 :          2 :     }
#     137                 :            : 
#     138                 :            :     // BlockUntilSyncedToCurrentChain should return false before index is started.
#     139                 :          2 :     BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
#     140                 :            : 
#     141                 :          2 :     BOOST_REQUIRE(filter_index.Start(m_node.chainman->ActiveChainstate()));
#     142                 :            : 
#     143                 :            :     // Allow filter index to catch up with the block index.
#     144                 :          2 :     constexpr int64_t timeout_ms = 10 * 1000;
#     145                 :          2 :     int64_t time_start = GetTimeMillis();
#     146         [ +  + ]:          4 :     while (!filter_index.BlockUntilSyncedToCurrentChain()) {
#     147                 :          2 :         BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
#     148                 :          2 :         UninterruptibleSleep(std::chrono::milliseconds{100});
#     149                 :          2 :     }
#     150                 :            : 
#     151                 :            :     // Check that filter index has all blocks that were in the chain before it started.
#     152                 :          2 :     {
#     153                 :          2 :         LOCK(cs_main);
#     154                 :          2 :         const CBlockIndex* block_index;
#     155                 :          2 :         for (block_index = m_node.chainman->ActiveChain().Genesis();
#     156         [ +  + ]:        204 :              block_index != nullptr;
#     157                 :        202 :              block_index = m_node.chainman->ActiveChain().Next(block_index)) {
#     158                 :        202 :             CheckFilterLookups(filter_index, block_index, last_header);
#     159                 :        202 :         }
#     160                 :          2 :     }
#     161                 :            : 
#     162                 :            :     // Create two forks.
#     163                 :          2 :     const CBlockIndex* tip;
#     164                 :          2 :     {
#     165                 :          2 :         LOCK(cs_main);
#     166                 :          2 :         tip = m_node.chainman->ActiveChain().Tip();
#     167                 :          2 :     }
#     168                 :          2 :     CKey coinbase_key_A, coinbase_key_B;
#     169                 :          2 :     coinbase_key_A.MakeNewKey(true);
#     170                 :          2 :     coinbase_key_B.MakeNewKey(true);
#     171                 :          2 :     CScript coinbase_script_pub_key_A = GetScriptForDestination(PKHash(coinbase_key_A.GetPubKey()));
#     172                 :          2 :     CScript coinbase_script_pub_key_B = GetScriptForDestination(PKHash(coinbase_key_B.GetPubKey()));
#     173                 :          2 :     std::vector<std::shared_ptr<CBlock>> chainA, chainB;
#     174                 :          2 :     BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key_A, 10, chainA));
#     175                 :          2 :     BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key_B, 10, chainB));
#     176                 :            : 
#     177                 :            :     // Check that new blocks on chain A get indexed.
#     178                 :          2 :     uint256 chainA_last_header = last_header;
#     179         [ +  + ]:          6 :     for (size_t i = 0; i < 2; i++) {
#     180                 :          4 :         const auto& block = chainA[i];
#     181                 :          4 :         BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
#     182                 :          4 :     }
#     183         [ +  + ]:          6 :     for (size_t i = 0; i < 2; i++) {
#     184                 :          4 :         const auto& block = chainA[i];
#     185                 :          4 :         const CBlockIndex* block_index;
#     186                 :          4 :         {
#     187                 :          4 :             LOCK(cs_main);
#     188                 :          4 :             block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());
#     189                 :          4 :         }
#     190                 :            : 
#     191                 :          4 :         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
#     192                 :          4 :         CheckFilterLookups(filter_index, block_index, chainA_last_header);
#     193                 :          4 :     }
#     194                 :            : 
#     195                 :            :     // Reorg to chain B.
#     196                 :          2 :     uint256 chainB_last_header = last_header;
#     197         [ +  + ]:          8 :     for (size_t i = 0; i < 3; i++) {
#     198                 :          6 :         const auto& block = chainB[i];
#     199                 :          6 :         BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
#     200                 :          6 :     }
#     201         [ +  + ]:          8 :     for (size_t i = 0; i < 3; i++) {
#     202                 :          6 :         const auto& block = chainB[i];
#     203                 :          6 :         const CBlockIndex* block_index;
#     204                 :          6 :         {
#     205                 :          6 :             LOCK(cs_main);
#     206                 :          6 :             block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());
#     207                 :          6 :         }
#     208                 :            : 
#     209                 :          6 :         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
#     210                 :          6 :         CheckFilterLookups(filter_index, block_index, chainB_last_header);
#     211                 :          6 :     }
#     212                 :            : 
#     213                 :            :     // Check that filters for stale blocks on A can be retrieved.
#     214                 :          2 :     chainA_last_header = last_header;
#     215         [ +  + ]:          6 :     for (size_t i = 0; i < 2; i++) {
#     216                 :          4 :         const auto& block = chainA[i];
#     217                 :          4 :         const CBlockIndex* block_index;
#     218                 :          4 :         {
#     219                 :          4 :             LOCK(cs_main);
#     220                 :          4 :             block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());
#     221                 :          4 :         }
#     222                 :            : 
#     223                 :          4 :         BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
#     224                 :          4 :         CheckFilterLookups(filter_index, block_index, chainA_last_header);
#     225                 :          4 :     }
#     226                 :            : 
#     227                 :            :     // Reorg back to chain A.
#     228         [ +  + ]:          6 :      for (size_t i = 2; i < 4; i++) {
#     229                 :          4 :          const auto& block = chainA[i];
#     230                 :          4 :          BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
#     231                 :          4 :      }
#     232                 :            : 
#     233                 :            :      // Check that chain A and B blocks can be retrieved.
#     234                 :          2 :      chainA_last_header = last_header;
#     235                 :          2 :      chainB_last_header = last_header;
#     236         [ +  + ]:          8 :      for (size_t i = 0; i < 3; i++) {
#     237                 :          6 :          const CBlockIndex* block_index;
#     238                 :            : 
#     239                 :          6 :          {
#     240                 :          6 :              LOCK(cs_main);
#     241                 :          6 :              block_index = m_node.chainman->m_blockman.LookupBlockIndex(chainA[i]->GetHash());
#     242                 :          6 :          }
#     243                 :          6 :          BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
#     244                 :          6 :          CheckFilterLookups(filter_index, block_index, chainA_last_header);
#     245                 :            : 
#     246                 :          6 :          {
#     247                 :          6 :              LOCK(cs_main);
#     248                 :          6 :              block_index = m_node.chainman->m_blockman.LookupBlockIndex(chainB[i]->GetHash());
#     249                 :          6 :          }
#     250                 :          6 :          BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
#     251                 :          6 :          CheckFilterLookups(filter_index, block_index, chainB_last_header);
#     252                 :          6 :      }
#     253                 :            : 
#     254                 :            :     // Test lookups for a range of filters/hashes.
#     255                 :          2 :     std::vector<BlockFilter> filters;
#     256                 :          2 :     std::vector<uint256> filter_hashes;
#     257                 :            : 
#     258                 :          2 :     {
#     259                 :          2 :         LOCK(cs_main);
#     260                 :          2 :         tip = m_node.chainman->ActiveChain().Tip();
#     261                 :          2 :     }
#     262                 :          2 :     BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters));
#     263                 :          2 :     BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes));
#     264                 :            : 
#     265                 :          2 :     assert(tip->nHeight >= 0);
#     266                 :          0 :     BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1U);
#     267                 :          2 :     BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1U);
#     268                 :            : 
#     269                 :          2 :     filters.clear();
#     270                 :          2 :     filter_hashes.clear();
#     271                 :            : 
#     272                 :          2 :     filter_index.Interrupt();
#     273                 :          2 :     filter_index.Stop();
#     274                 :          2 : }
#     275                 :            : 
#     276                 :            : BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
#     277                 :          2 : {
#     278                 :          2 :     BlockFilterIndex* filter_index;
#     279                 :            : 
#     280                 :          2 :     filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
#     281                 :          2 :     BOOST_CHECK(filter_index == nullptr);
#     282                 :            : 
#     283                 :          2 :     BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
#     284                 :            : 
#     285                 :          2 :     filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
#     286                 :          2 :     BOOST_CHECK(filter_index != nullptr);
#     287                 :          2 :     BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);
#     288                 :            : 
#     289                 :            :     // Initialize returns false if index already exists.
#     290                 :          2 :     BOOST_CHECK(!InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
#     291                 :            : 
#     292                 :          2 :     int iter_count = 0;
#     293                 :          2 :     ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; });
#     294                 :          2 :     BOOST_CHECK_EQUAL(iter_count, 1);
#     295                 :            : 
#     296                 :          2 :     BOOST_CHECK(DestroyBlockFilterIndex(BlockFilterType::BASIC));
#     297                 :            : 
#     298                 :            :     // Destroy returns false because index was already destroyed.
#     299                 :          2 :     BOOST_CHECK(!DestroyBlockFilterIndex(BlockFilterType::BASIC));
#     300                 :            : 
#     301                 :          2 :     filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
#     302                 :          2 :     BOOST_CHECK(filter_index == nullptr);
#     303                 :            : 
#     304                 :            :     // Reinitialize index.
#     305                 :          2 :     BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
#     306                 :            : 
#     307                 :          2 :     DestroyAllBlockFilterIndexes();
#     308                 :            : 
#     309                 :          2 :     filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
#     310                 :          2 :     BOOST_CHECK(filter_index == nullptr);
#     311                 :          2 : }
#     312                 :            : 
#     313                 :            : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a