/root/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 | 0 | { |
15 | 0 | std::vector<unsigned char> ret(CeilDiv(bits.size(), 8u)); |
16 | 0 | for (unsigned int p = 0; p < bits.size(); p++) { |
17 | 0 | ret[p / 8] |= bits[p] << (p % 8); |
18 | 0 | } |
19 | 0 | return ret; |
20 | 0 | } |
21 | | |
22 | | std::vector<bool> BytesToBits(const std::vector<unsigned char>& bytes) |
23 | 0 | { |
24 | 0 | std::vector<bool> ret(bytes.size() * 8); |
25 | 0 | for (unsigned int p = 0; p < ret.size(); p++) { |
26 | 0 | ret[p] = (bytes[p / 8] & (1 << (p % 8))) != 0; |
27 | 0 | } |
28 | 0 | return ret; |
29 | 0 | } |
30 | | |
31 | | CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<Txid>* txids) |
32 | 0 | { |
33 | 0 | header = static_cast<const CBlockHeader&>(block); |
34 | |
|
35 | 0 | std::vector<bool> vMatch; |
36 | 0 | std::vector<Txid> vHashes; |
37 | |
|
38 | 0 | vMatch.reserve(block.vtx.size()); |
39 | 0 | vHashes.reserve(block.vtx.size()); |
40 | |
|
41 | 0 | for (unsigned int i = 0; i < block.vtx.size(); i++) |
42 | 0 | { |
43 | 0 | const Txid& hash{block.vtx[i]->GetHash()}; |
44 | 0 | if (txids && txids->contains(hash)) { |
45 | 0 | vMatch.push_back(true); |
46 | 0 | } else if (filter && filter->IsRelevantAndUpdate(*block.vtx[i])) { |
47 | 0 | vMatch.push_back(true); |
48 | 0 | vMatchedTxn.emplace_back(i, hash); |
49 | 0 | } else { |
50 | 0 | vMatch.push_back(false); |
51 | 0 | } |
52 | 0 | vHashes.push_back(hash); |
53 | 0 | } |
54 | |
|
55 | 0 | txn = CPartialMerkleTree(vHashes, vMatch); |
56 | 0 | } |
57 | | |
58 | | // NOLINTNEXTLINE(misc-no-recursion) |
59 | 0 | 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 | 0 | assert(vTxid.size() != 0); |
63 | 0 | if (height == 0) { |
64 | | // hash at height 0 is the txids themselves |
65 | 0 | return vTxid[pos].ToUint256(); |
66 | 0 | } else { |
67 | | // calculate left hash |
68 | 0 | 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 | 0 | if (pos*2+1 < CalcTreeWidth(height-1)) |
71 | 0 | right = CalcHash(height-1, pos*2+1, vTxid); |
72 | 0 | else |
73 | 0 | right = left; |
74 | | // combine subhashes |
75 | 0 | return Hash(left, right); |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | | // NOLINTNEXTLINE(misc-no-recursion) |
80 | 0 | 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 | 0 | bool fParentOfMatch = false; |
83 | 0 | for (unsigned int p = pos << height; p < (pos+1) << height && p < nTransactions; p++) |
84 | 0 | fParentOfMatch |= vMatch[p]; |
85 | | // store as flag bit |
86 | 0 | vBits.push_back(fParentOfMatch); |
87 | 0 | if (height==0 || !fParentOfMatch) { |
88 | | // if at height 0, or nothing interesting below, store hash and stop |
89 | 0 | vHash.push_back(CalcHash(height, pos, vTxid)); |
90 | 0 | } else { |
91 | | // otherwise, don't store any hash, but descend into the subtrees |
92 | 0 | TraverseAndBuild(height-1, pos*2, vTxid, vMatch); |
93 | 0 | if (pos*2+1 < CalcTreeWidth(height-1)) |
94 | 0 | TraverseAndBuild(height-1, pos*2+1, vTxid, vMatch); |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | // NOLINTNEXTLINE(misc-no-recursion) |
99 | 0 | uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<Txid> &vMatch, std::vector<unsigned int> &vnIndex) { |
100 | 0 | if (nBitsUsed >= vBits.size()) { |
101 | | // overflowed the bits array - failure |
102 | 0 | fBad = true; |
103 | 0 | return uint256(); |
104 | 0 | } |
105 | 0 | bool fParentOfMatch = vBits[nBitsUsed++]; |
106 | 0 | if (height==0 || !fParentOfMatch) { |
107 | | // if at height 0, or nothing interesting below, use stored hash and do not descend |
108 | 0 | if (nHashUsed >= vHash.size()) { |
109 | | // overflowed the hash array - failure |
110 | 0 | fBad = true; |
111 | 0 | return uint256(); |
112 | 0 | } |
113 | 0 | const uint256 &hash = vHash[nHashUsed++]; |
114 | 0 | if (height==0 && fParentOfMatch) { // in case of height 0, we have a matched txid |
115 | 0 | vMatch.push_back(Txid::FromUint256(hash)); |
116 | 0 | vnIndex.push_back(pos); |
117 | 0 | } |
118 | 0 | return hash; |
119 | 0 | } else { |
120 | | // otherwise, descend into the subtrees to extract matched txids and hashes |
121 | 0 | uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch, vnIndex), right; |
122 | 0 | if (pos*2+1 < CalcTreeWidth(height-1)) { |
123 | 0 | right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch, vnIndex); |
124 | 0 | 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 | 0 | fBad = true; |
128 | 0 | } |
129 | 0 | } else { |
130 | 0 | right = left; |
131 | 0 | } |
132 | | // and combine them before returning |
133 | 0 | return Hash(left, right); |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | 0 | CPartialMerkleTree::CPartialMerkleTree(const std::vector<Txid> &vTxid, const std::vector<bool> &vMatch) : nTransactions(vTxid.size()), fBad(false) { |
138 | | // reset state |
139 | 0 | vBits.clear(); |
140 | 0 | vHash.clear(); |
141 | | |
142 | | // calculate height of tree |
143 | 0 | int nHeight = 0; |
144 | 0 | while (CalcTreeWidth(nHeight) > 1) |
145 | 0 | nHeight++; |
146 | | |
147 | | // traverse the partial tree |
148 | 0 | TraverseAndBuild(nHeight, 0, vTxid, vMatch); |
149 | 0 | } |
150 | | |
151 | 0 | CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {} |
152 | | |
153 | 0 | uint256 CPartialMerkleTree::ExtractMatches(std::vector<Txid> &vMatch, std::vector<unsigned int> &vnIndex) { |
154 | 0 | vMatch.clear(); |
155 | | // An empty set will not work |
156 | 0 | if (nTransactions == 0) |
157 | 0 | return uint256(); |
158 | | // check for excessively high numbers of transactions |
159 | 0 | 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 | 0 | 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 | 0 | if (vBits.size() < vHash.size()) |
166 | 0 | return uint256(); |
167 | | // calculate height of tree |
168 | 0 | int nHeight = 0; |
169 | 0 | while (CalcTreeWidth(nHeight) > 1) |
170 | 0 | nHeight++; |
171 | | // traverse the partial tree |
172 | 0 | unsigned int nBitsUsed = 0, nHashUsed = 0; |
173 | 0 | uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch, vnIndex); |
174 | | // verify that no problems occurred during the tree traversal |
175 | 0 | if (fBad) |
176 | 0 | return uint256(); |
177 | | // verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence) |
178 | 0 | if (CeilDiv(nBitsUsed, 8u) != CeilDiv(vBits.size(), 8u)) |
179 | 0 | return uint256(); |
180 | | // verify that all hashes were consumed |
181 | 0 | if (nHashUsed != vHash.size()) |
182 | 0 | return uint256(); |
183 | 0 | return hashMerkleRoot; |
184 | 0 | } |