LCOV - code coverage report
Current view: top level - src/test - blockencodings_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 97.7 % 301 294
Test Date: 2026-03-16 05:20:51 Functions: 100.0 % 23 23
Branches: 49.6 % 1404 696

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2011-present 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 <blockencodings.h>
       6                 :             : #include <chainparams.h>
       7                 :             : #include <consensus/merkle.h>
       8                 :             : #include <pow.h>
       9                 :             : #include <streams.h>
      10                 :             : #include <test/util/random.h>
      11                 :             : #include <test/util/txmempool.h>
      12                 :             : 
      13                 :             : #include <test/util/common.h>
      14                 :             : #include <test/util/setup_common.h>
      15                 :             : 
      16                 :             : #include <boost/test/unit_test.hpp>
      17                 :             : 
      18                 :             : const std::vector<std::pair<Wtxid, CTransactionRef>> empty_extra_txn;
      19                 :             : 
      20                 :             : BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegTestingSetup)
      21                 :             : 
      22                 :           6 : static CMutableTransaction BuildTransactionTestCase() {
      23                 :           6 :     CMutableTransaction tx;
      24         [ +  - ]:           6 :     tx.vin.resize(1);
      25                 :           6 :     tx.vin[0].scriptSig.resize(10);
      26         [ +  - ]:           6 :     tx.vout.resize(1);
      27                 :           6 :     tx.vout[0].nValue = 42;
      28                 :           6 :     return tx;
      29                 :           0 : }
      30                 :             : 
      31                 :           4 : static CBlock BuildBlockTestCase(FastRandomContext& ctx) {
      32                 :           4 :     CBlock block;
      33         [ +  - ]:           4 :     CMutableTransaction tx = BuildTransactionTestCase();
      34                 :             : 
      35         [ +  - ]:           4 :     block.vtx.resize(3);
      36   [ +  -  -  + ]:           8 :     block.vtx[0] = MakeTransactionRef(tx);
      37                 :           4 :     block.nVersion = 42;
      38                 :           4 :     block.hashPrevBlock = ctx.rand256();
      39                 :           4 :     block.nBits = 0x207fffff;
      40                 :             : 
      41         [ +  - ]:           4 :     tx.vin[0].prevout.hash = Txid::FromUint256(ctx.rand256());
      42                 :           4 :     tx.vin[0].prevout.n = 0;
      43   [ +  -  -  + ]:           8 :     block.vtx[1] = MakeTransactionRef(tx);
      44                 :             : 
      45         [ +  - ]:           4 :     tx.vin.resize(10);
      46   [ -  +  +  + ]:          44 :     for (size_t i = 0; i < tx.vin.size(); i++) {
      47                 :          40 :         tx.vin[i].prevout.hash = Txid::FromUint256(ctx.rand256());
      48                 :          40 :         tx.vin[i].prevout.n = 0;
      49                 :             :     }
      50   [ +  -  -  + ]:           8 :     block.vtx[2] = MakeTransactionRef(tx);
      51                 :             : 
      52                 :           4 :     bool mutated;
      53         [ +  - ]:           4 :     block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);
      54         [ -  + ]:           4 :     assert(!mutated);
      55   [ +  -  +  -  :           6 :     while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;
             +  -  +  + ]
      56                 :           4 :     return block;
      57                 :           4 : }
      58                 :             : 
      59                 :             : // Number of shared use_counts we expect for a tx we haven't touched
      60                 :             : // (block + mempool entry + our copy from the GetSharedTx call)
      61                 :             : constexpr long SHARED_TX_OFFSET{3};
      62                 :             : 
      63   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      64                 :             : {
      65         [ -  + ]:           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
      66                 :           1 :     TestMemPoolEntryHelper entry;
      67                 :           1 :     auto rand_ctx(FastRandomContext(uint256{42}));
      68         [ +  - ]:           1 :     CBlock block(BuildBlockTestCase(rand_ctx));
      69                 :             : 
      70   [ +  -  +  - ]:           1 :     LOCK2(cs_main, pool.cs);
      71   [ +  -  +  - ]:           1 :     TryAddToMempool(pool, entry.FromTx(block.vtx[2]));
      72   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
             +  -  +  - ]
      73                 :             : 
      74                 :             :     // Do a simple ShortTxIDs RT
      75                 :           1 :     {
      76         [ +  - ]:           1 :         CBlockHeaderAndShortTxIDs shortIDs{block, rand_ctx.rand64()};
      77                 :             : 
      78                 :           1 :         DataStream stream{};
      79         [ +  - ]:           1 :         stream << shortIDs;
      80                 :             : 
      81                 :           1 :         CBlockHeaderAndShortTxIDs shortIDs2;
      82         [ +  - ]:           1 :         stream >> shortIDs2;
      83                 :             : 
      84                 :           1 :         PartiallyDownloadedBlock partialBlock(&pool);
      85   [ +  -  +  -  :           2 :         BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK);
             +  -  +  - ]
      86   [ +  -  +  -  :           2 :         BOOST_CHECK( partialBlock.IsTxAvailable(0));
             +  -  +  - ]
      87   [ +  -  +  -  :           2 :         BOOST_CHECK(!partialBlock.IsTxAvailable(1));
             +  -  +  - ]
      88   [ +  -  +  -  :           2 :         BOOST_CHECK( partialBlock.IsTxAvailable(2));
             +  -  +  - ]
      89                 :             : 
      90   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 1);
             +  -  +  - ]
      91                 :             : 
      92         [ +  - ]:           1 :         size_t poolSize = pool.size();
      93         [ +  - ]:           1 :         pool.removeRecursive(*block.vtx[2], MemPoolRemovalReason::REPLACED);
      94   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(pool.size(), poolSize - 1);
                   +  - ]
      95                 :             : 
      96                 :           1 :         CBlock block2;
      97                 :           1 :         {
      98         [ +  - ]:           1 :             PartiallyDownloadedBlock tmp = partialBlock;
      99   [ +  -  +  -  :           2 :             BOOST_CHECK(partialBlock.FillBlock(block2, {}, /*segwit_active=*/true) == READ_STATUS_INVALID); // No transactions
             +  -  +  - ]
     100         [ +  - ]:           1 :             partialBlock = tmp;
     101                 :           0 :         }
     102                 :             : 
     103                 :             :         // Wrong transaction
     104                 :           1 :         {
     105         [ +  - ]:           1 :             PartiallyDownloadedBlock tmp = partialBlock;
     106   [ +  -  +  +  :           2 :             partialBlock.FillBlock(block2, {block.vtx[2]}, /*segwit_active=*/true); // Current implementation doesn't check txn here, but don't require that
          +  -  -  -  -  
                      - ]
     107         [ +  - ]:           1 :             partialBlock = tmp;
     108                 :           0 :         }
     109                 :           1 :         bool mutated;
     110   [ +  -  +  -  :           2 :         BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
                   +  - ]
     111                 :             : 
     112                 :           1 :         CBlock block3;
     113   [ +  -  +  -  :           4 :         BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[1]}, /*segwit_active=*/true) == READ_STATUS_OK);
          +  -  +  -  +  
          +  +  -  -  -  
                   -  - ]
     114   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());
          +  -  +  -  +  
                -  +  - ]
     115   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
          +  -  +  -  +  
                      - ]
     116   [ +  -  +  - ]:           2 :         BOOST_CHECK(!mutated);
     117         [ +  - ]:           4 :     }
     118   [ +  -  +  -  :           6 : }
          +  -  +  -  +  
                      - ]
     119                 :             : 
     120                 :           2 : class TestHeaderAndShortIDs {
     121                 :             :     // Utility to encode custom CBlockHeaderAndShortTxIDs
     122                 :             : public:
     123                 :             :     CBlockHeader header;
     124                 :             :     uint64_t nonce;
     125                 :             :     std::vector<uint64_t> shorttxids;
     126                 :             :     std::vector<PrefilledTransaction> prefilledtxn;
     127                 :             : 
     128         [ +  - ]:           2 :     explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
     129                 :           2 :         DataStream stream{};
     130         [ +  - ]:           2 :         stream << orig;
     131         [ +  - ]:           4 :         stream >> *this;
     132                 :           0 :     }
     133                 :           2 :     explicit TestHeaderAndShortIDs(const CBlock& block, FastRandomContext& ctx) :
     134         [ +  - ]:           4 :         TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs{block, ctx.rand64()}) {}
     135                 :             : 
     136                 :           3 :     uint64_t GetShortID(const Wtxid& txhash) const {
     137                 :           3 :         DataStream stream{};
     138         [ +  - ]:           3 :         stream << *this;
     139                 :           3 :         CBlockHeaderAndShortTxIDs base;
     140         [ +  - ]:           3 :         stream >> base;
     141         [ +  - ]:           3 :         return base.GetShortID(txhash);
     142                 :           3 :     }
     143                 :             : 
     144                 :          14 :     SERIALIZE_METHODS(TestHeaderAndShortIDs, obj) { READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<CBlockHeaderAndShortTxIDs::SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn); }
     145                 :             : };
     146                 :             : 
     147   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     148                 :             : {
     149         [ -  + ]:           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
     150                 :           1 :     TestMemPoolEntryHelper entry;
     151                 :           1 :     auto rand_ctx(FastRandomContext(uint256{42}));
     152         [ +  - ]:           1 :     CBlock block(BuildBlockTestCase(rand_ctx));
     153                 :             : 
     154   [ +  -  +  - ]:           1 :     LOCK2(cs_main, pool.cs);
     155   [ +  -  +  - ]:           1 :     TryAddToMempool(pool, entry.FromTx(block.vtx[2]));
     156   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
             +  -  +  - ]
     157                 :             : 
     158         [ +  - ]:           1 :     Txid txhash;
     159                 :             : 
     160                 :             :     // Test with pre-forwarding tx 1, but not coinbase
     161                 :           1 :     {
     162         [ +  - ]:           1 :         TestHeaderAndShortIDs shortIDs(block, rand_ctx);
     163         [ +  - ]:           1 :         shortIDs.prefilledtxn.resize(1);
     164         [ -  + ]:           1 :         shortIDs.prefilledtxn[0] = {1, block.vtx[1]};
     165         [ +  - ]:           1 :         shortIDs.shorttxids.resize(2);
     166   [ +  -  +  - ]:           1 :         shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetWitnessHash());
     167   [ +  -  +  - ]:           1 :         shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetWitnessHash());
     168                 :             : 
     169                 :           1 :         DataStream stream{};
     170         [ +  - ]:           1 :         stream << shortIDs;
     171                 :             : 
     172                 :           1 :         CBlockHeaderAndShortTxIDs shortIDs2;
     173         [ +  - ]:           1 :         stream >> shortIDs2;
     174                 :             : 
     175                 :           1 :         PartiallyDownloadedBlock partialBlock(&pool);
     176   [ +  -  +  -  :           2 :         BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK);
             +  -  +  - ]
     177   [ +  -  +  -  :           2 :         BOOST_CHECK(!partialBlock.IsTxAvailable(0));
             +  -  +  - ]
     178   [ +  -  +  -  :           2 :         BOOST_CHECK( partialBlock.IsTxAvailable(1));
             +  -  +  - ]
     179   [ +  -  +  -  :           2 :         BOOST_CHECK( partialBlock.IsTxAvailable(2));
             +  -  +  - ]
     180                 :             : 
     181   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 1); // +1 because of partialBlock
             +  -  +  - ]
     182                 :             : 
     183                 :           1 :         CBlock block2;
     184                 :           1 :         {
     185         [ +  - ]:           1 :             PartiallyDownloadedBlock tmp = partialBlock;
     186   [ +  -  +  -  :           2 :             BOOST_CHECK(partialBlock.FillBlock(block2, {}, /*segwit_active=*/true) == READ_STATUS_INVALID); // No transactions
             +  -  +  - ]
     187         [ +  - ]:           1 :             partialBlock = tmp;
     188                 :           0 :         }
     189                 :             : 
     190                 :             :         // Wrong transaction
     191                 :           1 :         {
     192         [ +  - ]:           1 :             PartiallyDownloadedBlock tmp = partialBlock;
     193   [ +  -  +  +  :           2 :             partialBlock.FillBlock(block2, {block.vtx[1]}, /*segwit_active=*/true); // Current implementation doesn't check txn here, but don't require that
          +  -  -  -  -  
                      - ]
     194         [ +  - ]:           1 :             partialBlock = tmp;
     195                 :           0 :         }
     196   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 2); // +2 because of partialBlock and block2
             +  -  +  - ]
     197                 :           1 :         bool mutated;
     198   [ +  -  +  -  :           2 :         BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
                   +  - ]
     199                 :             : 
     200                 :           1 :         CBlock block3;
     201         [ +  - ]:           1 :         PartiallyDownloadedBlock partialBlockCopy = partialBlock;
     202   [ +  -  +  -  :           4 :         BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}, /*segwit_active=*/true) == READ_STATUS_OK);
          +  -  +  -  +  
          +  +  -  -  -  
                   -  - ]
     203   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString());
          +  -  +  -  +  
                -  +  - ]
     204   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
          +  -  +  -  +  
                      - ]
     205   [ +  -  +  -  :           2 :         BOOST_CHECK(!mutated);
                   +  - ]
     206                 :             : 
     207   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 3); // +2 because of partialBlock and block2 and block3
             +  -  +  - ]
     208                 :             : 
     209                 :           1 :         txhash = block.vtx[2]->GetHash();
     210                 :           1 :         block.vtx.clear();
     211                 :           1 :         block2.vtx.clear();
     212                 :           1 :         block3.vtx.clear();
     213   [ +  -  +  -  :           3 :         BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.
             +  -  +  - ]
     214                 :           3 :     }
     215   [ +  -  +  -  :           3 :     BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET - 1); // -1 because of block
          +  -  +  -  +  
                      - ]
     216   [ +  -  +  -  :           8 : }
          +  -  +  -  +  
                -  +  - ]
     217                 :             : 
     218   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     219                 :             : {
     220         [ -  + ]:           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
     221                 :           1 :     TestMemPoolEntryHelper entry;
     222                 :           1 :     auto rand_ctx(FastRandomContext(uint256{42}));
     223         [ +  - ]:           1 :     CBlock block(BuildBlockTestCase(rand_ctx));
     224                 :             : 
     225   [ +  -  +  - ]:           1 :     LOCK2(cs_main, pool.cs);
     226   [ +  -  +  - ]:           1 :     TryAddToMempool(pool, entry.FromTx(block.vtx[1]));
     227   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
             +  -  +  - ]
     228                 :             : 
     229         [ +  - ]:           1 :     Txid txhash;
     230                 :             : 
     231                 :             :     // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool
     232                 :           1 :     {
     233         [ +  - ]:           1 :         TestHeaderAndShortIDs shortIDs(block, rand_ctx);
     234         [ +  - ]:           1 :         shortIDs.prefilledtxn.resize(2);
     235         [ -  + ]:           1 :         shortIDs.prefilledtxn[0] = {0, block.vtx[0]};
     236         [ -  + ]:           1 :         shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1
     237         [ +  - ]:           1 :         shortIDs.shorttxids.resize(1);
     238   [ +  -  +  - ]:           1 :         shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetWitnessHash());
     239                 :             : 
     240                 :           1 :         DataStream stream{};
     241         [ +  - ]:           1 :         stream << shortIDs;
     242                 :             : 
     243                 :           1 :         CBlockHeaderAndShortTxIDs shortIDs2;
     244         [ +  - ]:           1 :         stream >> shortIDs2;
     245                 :             : 
     246                 :           1 :         PartiallyDownloadedBlock partialBlock(&pool);
     247   [ +  -  +  -  :           2 :         BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK);
             +  -  +  - ]
     248   [ +  -  +  -  :           2 :         BOOST_CHECK( partialBlock.IsTxAvailable(0));
             +  -  +  - ]
     249   [ +  -  +  -  :           2 :         BOOST_CHECK( partialBlock.IsTxAvailable(1));
             +  -  +  - ]
     250   [ +  -  +  -  :           2 :         BOOST_CHECK( partialBlock.IsTxAvailable(2));
             +  -  +  - ]
     251                 :             : 
     252   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()).use_count(), SHARED_TX_OFFSET + 1);
             +  -  +  - ]
     253                 :             : 
     254                 :           1 :         CBlock block2;
     255         [ +  - ]:           1 :         PartiallyDownloadedBlock partialBlockCopy = partialBlock;
     256   [ +  -  +  -  :           2 :         BOOST_CHECK(partialBlock.FillBlock(block2, {}, /*segwit_active=*/true) == READ_STATUS_OK);
             +  -  +  - ]
     257   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
          +  -  +  -  +  
                -  +  - ]
     258                 :           1 :         bool mutated;
     259   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
          +  -  +  -  +  
                      - ]
     260   [ +  -  +  - ]:           2 :         BOOST_CHECK(!mutated);
     261                 :             : 
     262                 :           1 :         txhash = block.vtx[1]->GetHash();
     263                 :           1 :         block.vtx.clear();
     264                 :           1 :         block2.vtx.clear();
     265   [ +  -  +  -  :           3 :         BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.
             +  -  +  - ]
     266                 :           3 :     }
     267   [ +  -  +  -  :           3 :     BOOST_CHECK_EQUAL(pool.get(txhash).use_count(), SHARED_TX_OFFSET - 1); // -1 because of block
          +  -  +  -  +  
                      - ]
     268   [ +  -  +  -  :           6 : }
                   +  - ]
     269                 :             : 
     270   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     271                 :             : {
     272         [ -  + ]:           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
     273                 :           1 :     CMutableTransaction coinbase = BuildTransactionTestCase();
     274                 :             : 
     275                 :           1 :     CBlock block;
     276                 :           1 :     auto rand_ctx(FastRandomContext(uint256{42}));
     277         [ +  - ]:           1 :     block.vtx.resize(1);
     278   [ +  -  -  + ]:           2 :     block.vtx[0] = MakeTransactionRef(std::move(coinbase));
     279                 :           1 :     block.nVersion = 42;
     280                 :           1 :     block.hashPrevBlock = rand_ctx.rand256();
     281                 :           1 :     block.nBits = 0x207fffff;
     282                 :             : 
     283                 :           1 :     bool mutated;
     284         [ +  - ]:           1 :     block.hashMerkleRoot = BlockMerkleRoot(block, &mutated);
     285         [ +  - ]:           1 :     assert(!mutated);
     286   [ +  -  +  -  :           1 :     while (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) ++block.nNonce;
             +  -  -  + ]
     287                 :             : 
     288                 :             :     // Test simple header round-trip with only coinbase
     289                 :           1 :     {
     290         [ +  - ]:           1 :         CBlockHeaderAndShortTxIDs shortIDs{block, rand_ctx.rand64()};
     291                 :             : 
     292                 :           1 :         DataStream stream{};
     293         [ +  - ]:           1 :         stream << shortIDs;
     294                 :             : 
     295                 :           1 :         CBlockHeaderAndShortTxIDs shortIDs2;
     296         [ +  - ]:           1 :         stream >> shortIDs2;
     297                 :             : 
     298                 :           1 :         PartiallyDownloadedBlock partialBlock(&pool);
     299   [ +  -  +  -  :           2 :         BOOST_CHECK(partialBlock.InitData(shortIDs2, empty_extra_txn) == READ_STATUS_OK);
             +  -  +  - ]
     300   [ +  -  +  -  :           2 :         BOOST_CHECK(partialBlock.IsTxAvailable(0));
                   +  - ]
     301                 :             : 
     302                 :           1 :         CBlock block2;
     303                 :           1 :         std::vector<CTransactionRef> vtx_missing;
     304   [ +  -  +  -  :           2 :         BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing, /*segwit_active=*/true) == READ_STATUS_OK);
             +  -  +  - ]
     305   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
          +  -  +  -  +  
                -  +  - ]
     306   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
          +  -  +  -  +  
                      - ]
     307   [ +  -  +  - ]:           2 :         BOOST_CHECK(!mutated);
     308                 :           4 :     }
     309                 :           2 : }
     310                 :             : 
     311   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(ReceiveWithExtraTransactions) {
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     312         [ -  + ]:           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
     313                 :           1 :     TestMemPoolEntryHelper entry;
     314                 :           1 :     auto rand_ctx(FastRandomContext(uint256{42}));
     315                 :             : 
     316         [ +  - ]:           1 :     CMutableTransaction mtx = BuildTransactionTestCase();
     317         [ +  - ]:           1 :     mtx.vin[0].prevout.hash = Txid::FromUint256(rand_ctx.rand256());
     318                 :           1 :     mtx.vin[0].prevout.n = 0;
     319         [ +  - ]:           1 :     const CTransactionRef non_block_tx = MakeTransactionRef(std::move(mtx));
     320                 :             : 
     321         [ +  - ]:           1 :     CBlock block(BuildBlockTestCase(rand_ctx));
     322                 :           1 :     std::vector<std::pair<Wtxid, CTransactionRef>> extra_txn;
     323         [ +  - ]:           1 :     extra_txn.resize(10);
     324                 :             : 
     325   [ +  -  +  - ]:           1 :     LOCK2(cs_main, pool.cs);
     326   [ +  -  +  - ]:           1 :     TryAddToMempool(pool, entry.FromTx(block.vtx[2]));
     327   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pool.get(block.vtx[2]->GetHash()).use_count(), SHARED_TX_OFFSET + 0);
             +  -  +  - ]
     328                 :             :     // Ensure the non_block_tx is actually not in the block
     329         [ +  + ]:           4 :     for (const auto &block_tx : block.vtx) {
     330   [ +  -  +  - ]:           3 :         BOOST_CHECK_NE(block_tx->GetHash(), non_block_tx->GetHash());
     331                 :             :     }
     332                 :             :     // Ensure block.vtx[1] is not in pool
     333   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.get(block.vtx[1]->GetHash()), nullptr);
             +  -  -  + ]
     334                 :             : 
     335                 :           1 :     {
     336         [ +  - ]:           1 :         const CBlockHeaderAndShortTxIDs cmpctblock{block, rand_ctx.rand64()};
     337                 :           1 :         PartiallyDownloadedBlock partial_block(&pool);
     338                 :           1 :         PartiallyDownloadedBlock partial_block_with_extra(&pool);
     339                 :             : 
     340   [ +  -  +  -  :           2 :         BOOST_CHECK(partial_block.InitData(cmpctblock, extra_txn) == READ_STATUS_OK);
             +  -  +  - ]
     341   [ +  -  +  -  :           2 :         BOOST_CHECK( partial_block.IsTxAvailable(0));
             +  -  +  - ]
     342   [ +  -  +  -  :           2 :         BOOST_CHECK(!partial_block.IsTxAvailable(1));
             +  -  +  - ]
     343   [ +  -  +  -  :           2 :         BOOST_CHECK( partial_block.IsTxAvailable(2));
                   +  - ]
     344                 :             : 
     345                 :             :         // Add an unrelated tx to extra_txn:
     346         [ -  + ]:           1 :         extra_txn[0] = {non_block_tx->GetWitnessHash(), non_block_tx};
     347                 :             :         // and a tx from the block that's not in the mempool:
     348         [ -  + ]:           1 :         extra_txn[1] = {block.vtx[1]->GetWitnessHash(), block.vtx[1]};
     349                 :             : 
     350   [ +  -  +  -  :           2 :         BOOST_CHECK(partial_block_with_extra.InitData(cmpctblock, extra_txn) == READ_STATUS_OK);
             +  -  +  - ]
     351   [ +  -  +  -  :           2 :         BOOST_CHECK(partial_block_with_extra.IsTxAvailable(0));
             +  -  +  - ]
     352                 :             :         // This transaction is now available via extra_txn:
     353   [ +  -  +  -  :           2 :         BOOST_CHECK(partial_block_with_extra.IsTxAvailable(1));
             +  -  +  - ]
     354   [ +  -  +  -  :           2 :         BOOST_CHECK(partial_block_with_extra.IsTxAvailable(2));
                   +  - ]
     355         [ +  - ]:           3 :     }
     356   [ +  -  +  - ]:           4 : }
     357                 :             : 
     358   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     359                 :           1 :     BlockTransactionsRequest req1;
     360                 :           1 :     req1.blockhash = m_rng.rand256();
     361         [ +  - ]:           1 :     req1.indexes.resize(4);
     362         [ +  - ]:           1 :     req1.indexes[0] = 0;
     363                 :           1 :     req1.indexes[1] = 1;
     364                 :           1 :     req1.indexes[2] = 3;
     365                 :           1 :     req1.indexes[3] = 4;
     366                 :             : 
     367                 :           1 :     DataStream stream{};
     368         [ +  - ]:           1 :     stream << req1;
     369                 :             : 
     370                 :           1 :     BlockTransactionsRequest req2;
     371         [ +  - ]:           1 :     stream >> req2;
     372                 :             : 
     373   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(req1.blockhash.ToString(), req2.blockhash.ToString());
             +  -  +  - ]
     374   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(req1.indexes.size(), req2.indexes.size());
             -  +  +  - ]
     375   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(req1.indexes[0], req2.indexes[0]);
     376   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(req1.indexes[1], req2.indexes[1]);
     377   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(req1.indexes[2], req2.indexes[2]);
     378   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]);
     379                 :           1 : }
     380                 :             : 
     381   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) {
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     382                 :             :     // Check that the highest legal index is decoded correctly
     383                 :           1 :     BlockTransactionsRequest req0;
     384                 :           1 :     req0.blockhash = m_rng.rand256();
     385         [ +  - ]:           1 :     req0.indexes.resize(1);
     386         [ +  - ]:           1 :     req0.indexes[0] = 0xffff;
     387                 :           1 :     DataStream stream{};
     388         [ +  - ]:           1 :     stream << req0;
     389                 :             : 
     390                 :           1 :     BlockTransactionsRequest req1;
     391         [ +  - ]:           1 :     stream >> req1;
     392   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(req0.indexes.size(), req1.indexes.size());
             -  +  +  - ]
     393   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(req0.indexes[0], req1.indexes[0]);
     394                 :           1 : }
     395                 :             : 
     396   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) {
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     397                 :             :     // Any set of index deltas that starts with N values that sum to (0x10000 - N)
     398                 :             :     // causes the edge-case overflow that was originally not checked for. Such
     399                 :             :     // a request cannot be created by serializing a real BlockTransactionsRequest
     400                 :             :     // due to the overflow, so here we'll serialize from raw deltas.
     401                 :           1 :     BlockTransactionsRequest req0;
     402                 :           1 :     req0.blockhash = m_rng.rand256();
     403         [ +  - ]:           1 :     req0.indexes.resize(3);
     404         [ +  - ]:           1 :     req0.indexes[0] = 0x7000;
     405                 :           1 :     req0.indexes[1] = 0x10000 - 0x7000 - 2;
     406                 :           1 :     req0.indexes[2] = 0;
     407                 :           1 :     DataStream stream{};
     408         [ +  - ]:           1 :     stream << req0.blockhash;
     409   [ -  +  +  - ]:           1 :     WriteCompactSize(stream, req0.indexes.size());
     410         [ +  - ]:           1 :     WriteCompactSize(stream, req0.indexes[0]);
     411         [ +  - ]:           1 :     WriteCompactSize(stream, req0.indexes[1]);
     412         [ +  - ]:           1 :     WriteCompactSize(stream, req0.indexes[2]);
     413                 :             : 
     414                 :           1 :     BlockTransactionsRequest req1;
     415                 :           1 :     try {
     416         [ -  + ]:           1 :         stream >> req1;
     417                 :             :         // before patch: deserialize above succeeds and this check fails, demonstrating the overflow
     418   [ #  #  #  #  :           0 :         BOOST_CHECK(req1.indexes[1] < req1.indexes[2]);
                   #  # ]
     419                 :             :         // this shouldn't be reachable before or after patch
     420   [ -  -  -  - ]:           1 :         BOOST_CHECK(0);
     421         [ -  + ]:           1 :     } catch(std::ios_base::failure &) {
     422                 :             :         // deserialize should fail
     423   [ +  -  +  - ]:           2 :         BOOST_CHECK(true); // Needed to suppress "Test case [...] did not check any assertions"
     424                 :           1 :     }
     425                 :           1 : }
     426                 :             : 
     427                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1