1 | <?php |
||
12 | class PartialMerkleTree extends Serializable |
||
13 | { |
||
14 | /** |
||
15 | * @var int |
||
16 | */ |
||
17 | private $elementCount; |
||
18 | |||
19 | /** |
||
20 | * @var BufferInterface[] |
||
21 | */ |
||
22 | private $vHashes = []; |
||
23 | |||
24 | /** |
||
25 | * @var array |
||
26 | */ |
||
27 | private $vFlagBits = []; |
||
28 | |||
29 | /** |
||
30 | * @var bool |
||
31 | */ |
||
32 | private $fBad = false; |
||
33 | |||
34 | /** |
||
35 | * Takes array of hashes and flag array only. Use PartialMerkleTree::create() instead of creating instance directly.. |
||
36 | * |
||
37 | * @param int $txCount |
||
38 | * @param array $vHashes |
||
39 | * @param array $vBits |
||
40 | */ |
||
41 | 24 | public function __construct($txCount = 0, array $vHashes = [], array $vBits = []) |
|
47 | |||
48 | /** |
||
49 | * Construct the Merkle tree |
||
50 | * |
||
51 | * @param int $txCount |
||
52 | * @param array $vTxHashes |
||
53 | * @param array $vMatch |
||
54 | * @return PartialMerkleTree |
||
55 | */ |
||
56 | 24 | public static function create($txCount, array $vTxHashes, array $vMatch) |
|
62 | |||
63 | /** |
||
64 | * Calculate tree width for a given height. |
||
65 | * |
||
66 | * @param int $height |
||
67 | * @return int |
||
68 | */ |
||
69 | 24 | public function calcTreeWidth($height) |
|
73 | |||
74 | /** |
||
75 | * Calculate the tree height. |
||
76 | * |
||
77 | * @return int |
||
78 | */ |
||
79 | 24 | public function calcTreeHeight() |
|
88 | |||
89 | /** |
||
90 | * @return int |
||
91 | */ |
||
92 | 24 | public function getTxCount() |
|
96 | |||
97 | /** |
||
98 | * @return BufferInterface[] |
||
99 | */ |
||
100 | 16 | public function getHashes() |
|
104 | |||
105 | /** |
||
106 | * @return array |
||
107 | */ |
||
108 | 16 | public function getFlagBits() |
|
112 | |||
113 | /** |
||
114 | * Calculate the hash for the given $height and $position |
||
115 | * |
||
116 | * @param int $height |
||
117 | * @param int $position |
||
118 | * @param \BitWasp\Buffertools\BufferInterface[] $vTxid |
||
119 | * @return \BitWasp\Buffertools\BufferInterface |
||
120 | */ |
||
121 | 24 | public function calculateHash($height, $position, array $vTxid) |
|
137 | |||
138 | /** |
||
139 | * Construct the list of Merkle Tree hashes |
||
140 | * |
||
141 | * @param int $height |
||
142 | * @param int $position |
||
143 | * @param array $vTxid - array of Txid's in the block |
||
144 | * @param array $vMatch - reference to array to populate |
||
145 | */ |
||
146 | 24 | public function traverseAndBuild($height, $position, array $vTxid, array &$vMatch) |
|
164 | |||
165 | /** |
||
166 | * Traverse the Merkle Tree hashes and extract those which have a matching bit. |
||
167 | * |
||
168 | * @param int $height |
||
169 | * @param int $position |
||
170 | * @param int $nBitsUsed |
||
171 | * @param int $nHashUsed |
||
172 | * @param BufferInterface[] $vMatch |
||
173 | * @return BufferInterface |
||
174 | */ |
||
175 | 24 | public function traverseAndExtract($height, $position, &$nBitsUsed, &$nHashUsed, &$vMatch) |
|
176 | { |
||
177 | 24 | if ($nBitsUsed >= count($this->vFlagBits)) { |
|
178 | $this->fBad = true; |
||
179 | return new Buffer(); |
||
180 | } |
||
181 | |||
182 | 24 | $parent = $this->vFlagBits[$nBitsUsed++]; |
|
183 | 24 | if (0 === $height || !$parent) { |
|
184 | 24 | if ($nHashUsed >= count($this->vHashes)) { |
|
185 | $this->fBad = true; |
||
186 | return new Buffer(); |
||
187 | } |
||
188 | 24 | $hash = $this->vHashes[$nHashUsed++]; |
|
189 | 24 | if ($height === 0 && $parent) { |
|
190 | 24 | $vMatch[] = $hash->flip(); |
|
191 | 18 | } |
|
192 | 24 | return $hash; |
|
193 | } else { |
||
194 | 16 | $left = $this->traverseAndExtract($height - 1, $position * 2, $nBitsUsed, $nHashUsed, $vMatch); |
|
195 | 16 | if (($position * 2 + 1) < $this->calcTreeWidth($height - 1)) { |
|
196 | 16 | $right = $this->traverseAndExtract($height - 1, ($position * 2 + 1), $nBitsUsed, $nHashUsed, $vMatch); |
|
197 | 16 | if ($right === $left) { |
|
198 | 4 | $this->fBad = true; |
|
199 | } |
||
200 | 12 | } else { |
|
201 | 8 | $right = $left; |
|
202 | } |
||
203 | |||
204 | 16 | return Hash::sha256d(Buffertools::concat($left, $right)); |
|
205 | } |
||
206 | } |
||
207 | |||
208 | /** |
||
209 | * Extract matches from the tree into provided $vMatch reference. |
||
210 | * |
||
211 | * @param BufferInterface[] $vMatch - reference to array of extracted 'matching' hashes |
||
212 | * @return BufferInterface - this will be the merkle root |
||
213 | * @throws \Exception |
||
214 | */ |
||
215 | 24 | public function extractMatches(array &$vMatch) |
|
253 | |||
254 | /** |
||
255 | * @return BufferInterface |
||
256 | */ |
||
257 | 4 | public function getBuffer() |
|
261 | } |
||
262 |