Coverage Report

Created: 2026-06-18 19:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/test/fuzz/merkle.cpp
Line
Count
Source
1
// Copyright (c) 2025-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 <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
0
uint256 ComputeMerkleRootFromPath(const CBlock& block, uint32_t position, const std::vector<uint256>& merkle_path) {
18
0
    if (position >= block.vtx.size()) {
  Branch (18:9): [True: 0, False: 0]
19
0
        throw std::out_of_range("Position out of range");
20
0
    }
21
22
0
    uint256 current_hash = block.vtx[position]->GetHash().ToUint256();
23
24
0
    for (const uint256& sibling : merkle_path) {
  Branch (24:33): [True: 0, False: 0]
25
0
        if (position % 2 == 0) {
  Branch (25:13): [True: 0, False: 0]
26
0
            current_hash = Hash(current_hash, sibling);
27
0
        } else {
28
0
            current_hash = Hash(sibling, current_hash);
29
0
        }
30
0
        position = position / 2;
31
0
    }
32
33
0
    return current_hash;
34
0
}
35
36
FUZZ_TARGET(merkle)
37
0
{
38
0
    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
39
40
0
    const bool with_witness = fuzzed_data_provider.ConsumeBool();
41
0
    std::optional<CBlock> block {ConsumeDeserializable<CBlock>(fuzzed_data_provider, with_witness ? TX_WITH_WITNESS : TX_NO_WITNESS)};
  Branch (41:86): [True: 0, False: 0]
42
0
    if (!block){
  Branch (42:9): [True: 0, False: 0]
43
0
        return;
44
0
    }
45
0
    const size_t num_txs = block->vtx.size();
46
0
    std::vector<uint256> tx_hashes;
47
0
    tx_hashes.reserve(num_txs);
48
49
0
    for (size_t i = 0; i < num_txs; ++i) {
  Branch (49:24): [True: 0, False: 0]
50
0
        tx_hashes.push_back(block->vtx[i]->GetHash().ToUint256());
51
0
    }
52
53
    // Test ComputeMerkleRoot
54
0
    bool mutated = fuzzed_data_provider.ConsumeBool(); // output param, initial value shouldn't matter
55
0
    const uint256 merkle_root = ComputeMerkleRoot(tx_hashes, fuzzed_data_provider.ConsumeBool() ? &mutated : nullptr);
  Branch (55:62): [True: 0, False: 0]
56
57
    // Basic sanity checks for ComputeMerkleRoot
58
0
    if (tx_hashes.size() == 1) {
  Branch (58:9): [True: 0, False: 0]
59
0
        assert(merkle_root == tx_hashes[0]);
  Branch (59:9): [True: 0, False: 0]
60
0
    }
61
62
63
0
    const uint256 block_merkle_root = BlockMerkleRoot(*block, &mutated);
64
0
    if (tx_hashes.size() == 1) {
  Branch (64:9): [True: 0, False: 0]
65
0
        assert(block_merkle_root == tx_hashes[0]);
  Branch (65:9): [True: 0, False: 0]
66
0
    }
67
68
0
    if (!block->vtx.empty()){
  Branch (68:9): [True: 0, False: 0]
69
0
        const uint256 block_witness_merkle_root = BlockWitnessMerkleRoot(*block);
70
0
        if (tx_hashes.size() == 1) {
  Branch (70:13): [True: 0, False: 0]
71
0
            assert(block_witness_merkle_root == uint256());
  Branch (71:13): [True: 0, False: 0]
72
0
        }
73
0
    }
74
75
    // Test TransactionMerklePath
76
0
    const uint32_t position = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, num_txs > 0 ? num_txs - 1 : 0);
  Branch (76:88): [True: 0, False: 0]
77
0
    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
0
    if (tx_hashes.size() > 1) {
  Branch (80:9): [True: 0, False: 0]
81
0
        uint256 merkle_root_from_merkle_path = ComputeMerkleRootFromPath(*block, position, merkle_path);
82
0
        assert(merkle_root_from_merkle_path == merkle_root);
  Branch (82:9): [True: 0, False: 0]
83
0
        assert(merkle_root_from_merkle_path == block_merkle_root);
  Branch (83:9): [True: 0, False: 0]
84
0
    }
85
86
    // Basic sanity checks for TransactionMerklePath
87
0
    assert(merkle_path.size() <= 32); // Maximum depth of a Merkle tree with 2^32 leaves
  Branch (87:5): [True: 0, False: 0]
88
0
    if (num_txs == 1 || num_txs == 0) {
  Branch (88:9): [True: 0, False: 0]
  Branch (88:25): [True: 0, False: 0]
89
0
        assert(merkle_path.empty()); // Single transaction has no path
  Branch (89:9): [True: 0, False: 0]
90
0
    }
91
92
0
}