Coverage Report

Created: 2026-04-29 19:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/merkleblock.cpp
Line
Count
Source
1
// Copyright (c) 2009-2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present The Bitcoin 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 <merkleblock.h>
7
8
#include <consensus/consensus.h>
9
#include <hash.h>
10
#include <util/overflow.h>
11
12
13
std::vector<unsigned char> BitsToBytes(const std::vector<bool>& bits)
14
185
{
15
185
    std::vector<unsigned char> ret(CeilDiv(bits.size(), 8u));
16
76.7k
    for (unsigned int p = 0; p < bits.size(); p++) {
17
76.5k
        ret[p / 8] |= bits[p] << (p % 8);
18
76.5k
    }
19
185
    return ret;
20
185
}
21
22
std::vector<bool> BytesToBits(const std::vector<unsigned char>& bytes)
23
187
{
24
187
    std::vector<bool> ret(bytes.size() * 8);
25
77.5k
    for (unsigned int p = 0; p < ret.size(); p++) {
26
77.3k
        ret[p] = (bytes[p / 8] & (1 << (p % 8))) != 0;
27
77.3k
    }
28
187
    return ret;
29
187
}
30
31
CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<Txid>* txids)
32
29
{
33
29
    header = static_cast<const CBlockHeader&>(block);
34
35
29
    std::vector<bool> vMatch;
36
29
    std::vector<Txid> vHashes;
37
38
29
    vMatch.reserve(block.vtx.size());
39
29
    vHashes.reserve(block.vtx.size());
40
41
147
    for (unsigned int i = 0; i < block.vtx.size(); i++)
42
118
    {
43
118
        const Txid& hash{block.vtx[i]->GetHash()};
44
118
        if (txids && txids->contains(hash)) {
45
19
            vMatch.push_back(true);
46
99
        } else if (filter && filter->IsRelevantAndUpdate(*block.vtx[i])) {
47
22
            vMatch.push_back(true);
48
22
            vMatchedTxn.emplace_back(i, hash);
49
77
        } else {
50
77
            vMatch.push_back(false);
51
77
        }
52
118
        vHashes.push_back(hash);
53
118
    }
54
55
29
    txn = CPartialMerkleTree(vHashes, vMatch);
56
29
}
57
58
// NOLINTNEXTLINE(misc-no-recursion)
59
143k
uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<Txid> &vTxid) {
60
    //we can never have zero txs in a merkle block, we always need the coinbase tx
61
    //if we do not have this assert, we can hit a memory access violation when indexing into vTxid
62
143k
    assert(vTxid.size() != 0);
63
143k
    if (height == 0) {
64
        // hash at height 0 is the txids themselves
65
90.9k
        return vTxid[pos].ToUint256();
66
90.9k
    } else {
67
        // calculate left hash
68
52.8k
        uint256 left = CalcHash(height-1, pos*2, vTxid), right;
69
        // calculate right hash if not beyond the end of the array - copy left hash otherwise
70
52.8k
        if (pos*2+1 < CalcTreeWidth(height-1))
71
52.6k
            right = CalcHash(height-1, pos*2+1, vTxid);
72
240
        else
73
240
            right = left;
74
        // combine subhashes
75
52.8k
        return Hash(left, right);
76
52.8k
    }
77
143k
}
78
79
// NOLINTNEXTLINE(misc-no-recursion)
80
76.6k
void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const std::vector<Txid> &vTxid, const std::vector<bool> &vMatch) {
81
    // determine whether this node is the parent of at least one matched txid
82
76.6k
    bool fParentOfMatch = false;
83
939k
    for (unsigned int p = pos << height; p < (pos+1) << height && p < nTransactions; p++)
84
862k
        fParentOfMatch |= vMatch[p];
85
    // store as flag bit
86
76.6k
    vBits.push_back(fParentOfMatch);
87
76.6k
    if (height==0 || !fParentOfMatch) {
88
        // if at height 0, or nothing interesting below, store hash and stop
89
38.3k
        vHash.push_back(CalcHash(height, pos, vTxid));
90
38.3k
    } else {
91
        // otherwise, don't store any hash, but descend into the subtrees
92
38.2k
        TraverseAndBuild(height-1, pos*2, vTxid, vMatch);
93
38.2k
        if (pos*2+1 < CalcTreeWidth(height-1))
94
38.1k
            TraverseAndBuild(height-1, pos*2+1, vTxid, vMatch);
95
38.2k
    }
96
76.6k
}
97
98
// NOLINTNEXTLINE(misc-no-recursion)
99
382k
uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<Txid> &vMatch, std::vector<unsigned int> &vnIndex) {
100
382k
    if (nBitsUsed >= vBits.size()) {
101
        // overflowed the bits array - failure
102
0
        fBad = true;
103
0
        return uint256();
104
0
    }
105
382k
    bool fParentOfMatch = vBits[nBitsUsed++];
106
382k
    if (height==0 || !fParentOfMatch) {
107
        // if at height 0, or nothing interesting below, use stored hash and do not descend
108
191k
        if (nHashUsed >= vHash.size()) {
109
            // overflowed the hash array - failure
110
0
            fBad = true;
111
0
            return uint256();
112
0
        }
113
191k
        const uint256 &hash = vHash[nHashUsed++];
114
191k
        if (height==0 && fParentOfMatch) { // in case of height 0, we have a matched txid
115
96.0k
            vMatch.push_back(Txid::FromUint256(hash));
116
96.0k
            vnIndex.push_back(pos);
117
96.0k
        }
118
191k
        return hash;
119
191k
    } else {
120
        // otherwise, descend into the subtrees to extract matched txids and hashes
121
191k
        uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch, vnIndex), right;
122
191k
        if (pos*2+1 < CalcTreeWidth(height-1)) {
123
190k
            right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch, vnIndex);
124
190k
            if (right == left) {
125
                // The left and right branches should never be identical, as the transaction
126
                // hashes covered by them must each be unique.
127
1
                fBad = true;
128
1
            }
129
190k
        } else {
130
606
            right = left;
131
606
        }
132
        // and combine them before returning
133
191k
        return Hash(left, right);
134
191k
    }
135
382k
}
136
137
198
CPartialMerkleTree::CPartialMerkleTree(const std::vector<Txid> &vTxid, const std::vector<bool> &vMatch) : nTransactions(vTxid.size()), fBad(false) {
138
    // reset state
139
198
    vBits.clear();
140
198
    vHash.clear();
141
142
    // calculate height of tree
143
198
    int nHeight = 0;
144
1.36k
    while (CalcTreeWidth(nHeight) > 1)
145
1.16k
        nHeight++;
146
147
    // traverse the partial tree
148
198
    TraverseAndBuild(nHeight, 0, vTxid, vMatch);
149
198
}
150
151
223
CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}
152
153
871
uint256 CPartialMerkleTree::ExtractMatches(std::vector<Txid> &vMatch, std::vector<unsigned int> &vnIndex) {
154
871
    vMatch.clear();
155
    // An empty set will not work
156
871
    if (nTransactions == 0)
157
0
        return uint256();
158
    // check for excessively high numbers of transactions
159
871
    if (nTransactions > MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT)
160
0
        return uint256();
161
    // there can never be more hashes provided than one for every txid
162
871
    if (vHash.size() > nTransactions)
163
0
        return uint256();
164
    // there must be at least one bit per node in the partial tree, and at least one node per hash
165
871
    if (vBits.size() < vHash.size())
166
0
        return uint256();
167
    // calculate height of tree
168
871
    int nHeight = 0;
169
6.46k
    while (CalcTreeWidth(nHeight) > 1)
170
5.59k
        nHeight++;
171
    // traverse the partial tree
172
871
    unsigned int nBitsUsed = 0, nHashUsed = 0;
173
871
    uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch, vnIndex);
174
    // verify that no problems occurred during the tree traversal
175
871
    if (fBad)
176
1
        return uint256();
177
    // verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)
178
870
    if (CeilDiv(nBitsUsed, 8u) != CeilDiv(vBits.size(), 8u))
179
0
        return uint256();
180
    // verify that all hashes were consumed
181
870
    if (nHashUsed != vHash.size())
182
0
        return uint256();
183
870
    return hashMerkleRoot;
184
870
}