LCOV - code coverage report
Current view: top level - src/test - blockencodings_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 97.7 % 301 294
Test Date: 2024-11-04 04:45:35 Functions: 100.0 % 23 23
Branches: 49.5 % 1294 641

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

Generated by: LCOV version 2.0-1