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

Generated by: LCOV version 1.14