LCOV - code coverage report
Current view: top level - src/test - blockencodings_tests.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 263 263 100.0 %
Date: 2022-04-21 14:51:19 Functions: 13 13 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: 4 6 66.7 %

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

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