LCOV - code coverage report
Current view: top level - src/test/fuzz - merkle.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 97.6 % 42 41
Test Date: 2025-07-10 04:10:27 Functions: 100.0 % 3 3
Branches: 67.7 % 62 42

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2025 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 <consensus/merkle.h>
       6                 :             : #include <test/fuzz/fuzz.h>
       7                 :             : #include <test/fuzz/FuzzedDataProvider.h>
       8                 :             : #include <test/fuzz/util.h>
       9                 :             : #include <test/util/str.h>
      10                 :             : #include <util/strencodings.h>
      11                 :             : #include <hash.h>
      12                 :             : 
      13                 :             : #include <cassert>
      14                 :             : #include <cstdint>
      15                 :             : #include <vector>
      16                 :             : 
      17                 :         148 : uint256 ComputeMerkleRootFromPath(const CBlock& block, uint32_t position, const std::vector<uint256>& merkle_path) {
      18         [ -  + ]:         148 :     if (position >= block.vtx.size()) {
      19         [ #  # ]:           0 :         throw std::out_of_range("Position out of range");
      20                 :             :     }
      21                 :             : 
      22                 :         148 :     uint256 current_hash = block.vtx[position]->GetHash();
      23                 :             : 
      24         [ +  + ]:         944 :     for (const uint256& sibling : merkle_path) {
      25         [ +  + ]:         796 :         if (position % 2 == 0) {
      26                 :         600 :             current_hash = Hash(current_hash, sibling);
      27                 :             :         } else {
      28                 :         196 :             current_hash = Hash(sibling, current_hash);
      29                 :             :         }
      30                 :         796 :         position = position / 2;
      31                 :             :     }
      32                 :             : 
      33                 :         148 :     return current_hash;
      34                 :             : }
      35                 :             : 
      36         [ +  - ]:         959 : FUZZ_TARGET(merkle)
      37                 :             : {
      38                 :         513 :     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
      39                 :             : 
      40                 :         513 :     const bool with_witness = fuzzed_data_provider.ConsumeBool();
      41         [ +  + ]:         728 :     std::optional<CBlock> block {ConsumeDeserializable<CBlock>(fuzzed_data_provider, with_witness ? TX_WITH_WITNESS : TX_NO_WITNESS)};
      42         [ +  + ]:         513 :     if (!block){
      43                 :         337 :         return;
      44                 :             :     }
      45         [ +  - ]:         176 :     const size_t num_txs = block->vtx.size();
      46                 :         176 :     std::vector<uint256> tx_hashes;
      47         [ +  - ]:         176 :     tx_hashes.reserve(num_txs);
      48                 :             : 
      49         [ +  + ]:      378773 :     for (size_t i = 0; i < num_txs; ++i) {
      50         [ +  - ]:      378597 :         tx_hashes.push_back(block->vtx[i]->GetHash());
      51                 :             :     }
      52                 :             : 
      53                 :             :     // Test ComputeMerkleRoot
      54                 :         176 :     bool mutated = fuzzed_data_provider.ConsumeBool();
      55   [ +  -  +  - ]:         176 :     const uint256 merkle_root = ComputeMerkleRoot(tx_hashes, &mutated);
      56                 :             : 
      57                 :             :     // Basic sanity checks for ComputeMerkleRoot
      58         [ +  + ]:         176 :     if (tx_hashes.size() == 1) {
      59         [ -  + ]:          25 :         assert(merkle_root == tx_hashes[0]);
      60                 :             :     }
      61                 :             : 
      62                 :             : 
      63         [ +  - ]:         176 :     const uint256 block_merkle_root = BlockMerkleRoot(*block, &mutated);
      64         [ +  + ]:         176 :     if (tx_hashes.size() == 1) {
      65         [ -  + ]:          25 :         assert(block_merkle_root == tx_hashes[0]);
      66                 :             :     }
      67                 :             : 
      68         [ +  + ]:         176 :     if (!block->vtx.empty()){
      69         [ +  - ]:         173 :         const uint256 block_witness_merkle_root = BlockWitnessMerkleRoot(*block, &mutated);
      70         [ +  + ]:         173 :         if (tx_hashes.size() == 1) {
      71         [ -  + ]:          25 :             assert(block_witness_merkle_root == uint256());
      72                 :             :         }
      73                 :             :     }
      74                 :             : 
      75                 :             :     // Test TransactionMerklePath
      76         [ +  + ]:         176 :     const uint32_t position = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, num_txs > 0 ? num_txs - 1 : 0);
      77         [ +  - ]:         176 :     std::vector<uint256> merkle_path = TransactionMerklePath(*block, position);
      78                 :             : 
      79                 :             :     // Check that the root we compute from TransactionMerklePath equals the same merkle_root and block_merkle_root
      80         [ +  + ]:         176 :     if (tx_hashes.size() > 1) {
      81         [ +  - ]:         148 :         uint256 merkle_root_from_merkle_path = ComputeMerkleRootFromPath(*block, position, merkle_path);
      82         [ -  + ]:         148 :         assert(merkle_root_from_merkle_path == merkle_root);
      83         [ -  + ]:         148 :         assert(merkle_root_from_merkle_path == block_merkle_root);
      84                 :             :     }
      85                 :             : 
      86                 :             :     // Basic sanity checks for TransactionMerklePath
      87         [ -  + ]:         176 :     assert(merkle_path.size() <= 32); // Maximum depth of a Merkle tree with 2^32 leaves
      88         [ +  + ]:         176 :     if (num_txs == 1 || num_txs == 0) {
      89         [ -  + ]:          28 :         assert(merkle_path.empty()); // Single transaction has no path
      90                 :             :     }
      91                 :             : 
      92                 :         513 : }
        

Generated by: LCOV version 2.0-1