LCOV - code coverage report
Current view: top level - src/test - merkle_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 80 80 100.0 %
Date: 2025-02-23 09:33:43 Functions: 4 4 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2015 The Bitcoin Core developers
       2             : // Copyright (c) 2019-2020 The PIVX Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "consensus/merkle.h"
       7             : #include "test/test_pivx.h"
       8             : 
       9             : #include <boost/test/unit_test.hpp>
      10             : 
      11             : BOOST_FIXTURE_TEST_SUITE(merkle_tests, TestingSetup)
      12             : 
      13             : // Older version of the merkle root computation code, for comparison.
      14          93 : static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::vector<uint256>& vMerkleTree)
      15             : {
      16          93 :     vMerkleTree.clear();
      17          93 :     vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
      18      120214 :     for (std::vector<CTransactionRef>::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it)
      19      120121 :         vMerkleTree.push_back((*it)->GetHash());
      20          93 :     int j = 0;
      21          93 :     bool mutated = false;
      22         856 :     for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
      23             :     {
      24      121045 :         for (int i = 0; i < nSize; i += 2)
      25             :         {
      26      120282 :             int i2 = std::min(i+1, nSize-1);
      27      120282 :             if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) {
      28             :                 // Two identical hashes at the end of the list at a particular level.
      29             :                 mutated = true;
      30             :             }
      31      120282 :             vMerkleTree.push_back(Hash(vMerkleTree[j+i].begin(), vMerkleTree[j+i].end(),
      32      120282 :                                        vMerkleTree[j+i2].begin(), vMerkleTree[j+i2].end()));
      33             :         }
      34         763 :         j += nSize;
      35             :     }
      36          93 :     if (fMutated) {
      37          93 :         *fMutated = mutated;
      38             :     }
      39          93 :     return (vMerkleTree.empty() ? uint256() : vMerkleTree.back());
      40             : }
      41             : 
      42             : // Older version of the merkle branch computation code, for comparison.
      43         376 : static std::vector<uint256> BlockGetMerkleBranch(const CBlock& block, const std::vector<uint256>& vMerkleTree, int nIndex)
      44             : {
      45         376 :     std::vector<uint256> vMerkleBranch;
      46         376 :     int j = 0;
      47        3478 :     for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
      48             :     {
      49        3102 :         int i = std::min(nIndex^1, nSize-1);
      50        3102 :         vMerkleBranch.push_back(vMerkleTree[j+i]);
      51        3102 :         nIndex >>= 1;
      52        3102 :         j += nSize;
      53             :     }
      54         376 :     return vMerkleBranch;
      55             : }
      56             : 
      57         143 : static inline int ctz(uint32_t i) {
      58         143 :     if (i == 0) return 0;
      59             :     int j = 0;
      60         380 :     while (!(i & 1)) {
      61         237 :         j++;
      62         237 :         i >>= 1;
      63             :     }
      64             :     return j;
      65             : }
      66             : 
      67           2 : BOOST_AUTO_TEST_CASE(merkle_test)
      68             : {
      69          33 :     for (int i = 0; i < 32; i++) {
      70             :         // Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 random sizes.
      71          47 :         int ntx = (i <= 16) ? i : 17 + (InsecureRandRange(4000));
      72             :         // Try up to 3 mutations.
      73         125 :         for (int mutate = 0; mutate <= 3; mutate++) {
      74         186 :             int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; // The last how many transactions to duplicate first.
      75         109 :             if (duplicate1 >= ntx) break; // Duplication of the entire tree results in a different root (it adds a level).
      76         103 :             int ntx1 = ntx + duplicate1; // The resulting number of transactions after the first duplication.
      77         149 :             int duplicate2 = mutate >= 2 ? 1 << ctz(ntx1) : 0; // Likewise for the second mutation.
      78         103 :             if (duplicate2 >= ntx1) break;
      79          97 :             int ntx2 = ntx1 + duplicate2;
      80         117 :             int duplicate3 = mutate >= 3 ? 1 << ctz(ntx2) : 0; // And for the the third mutation.
      81          97 :             if (duplicate3 >= ntx2) break;
      82          93 :             int ntx3 = ntx2 + duplicate3;
      83             :             // Build a block with ntx different transactions.
      84          93 :             CBlock block;
      85          93 :             block.vtx.resize(ntx);
      86      119219 :             for (int j = 0; j < ntx; j++) {
      87      119126 :                 CMutableTransaction mtx;
      88      119126 :                 mtx.nLockTime = j;
      89      119126 :                 block.vtx[j] = std::make_shared<const CTransaction>(mtx);
      90             :             }
      91             :             // Compute the root of the block before mutating it.
      92          93 :             bool unmutatedMutated = false;
      93          93 :             uint256 unmutatedRoot = BlockMerkleRoot(block, &unmutatedMutated);
      94         186 :             BOOST_CHECK(unmutatedMutated == false);
      95             :             // Optionally mutate by duplicating the last transactions, resulting in the same merkle root.
      96          93 :             block.vtx.resize(ntx3);
      97         252 :             for (int j = 0; j < duplicate1; j++) {
      98         159 :                 block.vtx[ntx + j] = block.vtx[ntx + j - duplicate1];
      99             :             }
     100         381 :             for (int j = 0; j < duplicate2; j++) {
     101         288 :                 block.vtx[ntx1 + j] = block.vtx[ntx1 + j - duplicate2];
     102             :             }
     103         641 :             for (int j = 0; j < duplicate3; j++) {
     104         548 :                 block.vtx[ntx2 + j] = block.vtx[ntx2 + j - duplicate3];
     105             :             }
     106             :             // Compute the merkle root and merkle tree using the old mechanism.
     107          93 :             bool oldMutated = false;
     108         186 :             std::vector<uint256> merkleTree;
     109          93 :             uint256 oldRoot = BlockBuildMerkleTree(block, &oldMutated, merkleTree);
     110             :             // Compute the merkle root using the new mechanism.
     111          93 :             bool newMutated = false;
     112          93 :             uint256 newRoot = BlockMerkleRoot(block, &newMutated);
     113         186 :             BOOST_CHECK(oldRoot == newRoot);
     114         186 :             BOOST_CHECK(newRoot == unmutatedRoot);
     115         279 :             BOOST_CHECK((newRoot == uint256()) == (ntx == 0));
     116         186 :             BOOST_CHECK(oldMutated == newMutated);
     117         186 :             BOOST_CHECK(newMutated == !!mutate);
     118             :             // If no mutation was done (once for every ntx value), try up to 16 branches.
     119          93 :             if (mutate == 0) {
     120         662 :                 for (int loop = 0; loop < std::min(ntx, 16); loop++) {
     121             :                     // If ntx <= 16, try all branches. Otherwise, try 16 random ones.
     122         376 :                     int mtx = loop;
     123         376 :                     if (ntx > 16) {
     124         240 :                         mtx = InsecureRandRange(ntx);
     125             :                     }
     126         752 :                     std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx);
     127         752 :                     std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);
     128         752 :                     BOOST_CHECK(oldBranch == newBranch);
     129         752 :                     BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot);
     130             :                 }
     131             :             }
     132             :         }
     133             :     }
     134           1 : }
     135             : 
     136             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14