Coverage Summary for Class: GenesisMerkleProofBuilder (co.rsk.mine)
Class |
Class, %
|
Method, %
|
Line, %
|
GenesisMerkleProofBuilder |
0%
(0/1)
|
0%
(0/6)
|
0%
(0/25)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2018 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 package co.rsk.mine;
19
20 import co.rsk.bitcoinj.core.*;
21 import org.bouncycastle.util.encoders.Hex;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.stream.Collectors;
26
27 /**
28 * Builds Merkle proofs with the format used since Genesis until RSKIP 92 activation
29 */
30 public class GenesisMerkleProofBuilder implements MerkleProofBuilder {
31
32 @Override
33 public byte[] buildFromMerkleHashes(
34 BtcBlock blockWithHeaderOnly,
35 List<String> merkleHashesString,
36 int blockTxnCount) {
37 List<Sha256Hash> merkleHashes = merkleHashesString.stream()
38 .map(mk -> Sha256Hash.wrapReversed(Hex.decode(mk)))
39 .collect(Collectors.toList());
40 int merkleTreeHeight = (int) Math.ceil(Math.log(blockTxnCount) / Math.log(2));
41
42 // bitlist will always have ones at the beginning because merkle branch is built for coinbase tx
43 List<Boolean> bitList = new ArrayList<>();
44 for (int i = 0; i < merkleHashes.size() + merkleTreeHeight; i++) {
45 bitList.add(i < merkleHashes.size());
46 }
47
48 // bits indicates which nodes are going to be used for building the partial merkle tree
49 // for more information please refer to {@link co.rsk.bitcoinj.core.PartialMerkleTree#buildFromLeaves } method
50 byte[] bits = new byte[(bitList.size() + 7) / 8];
51 for (int i = 0; i < bitList.size(); i++) {
52 if (bitList.get(i)) {
53 Utils.setBitLE(bits, i);
54 }
55 }
56
57 PartialMerkleTree bitcoinMergedMiningMerkleBranch = new PartialMerkleTree(blockWithHeaderOnly.getParams(), bits, merkleHashes, blockTxnCount);
58
59 return bitcoinMergedMiningMerkleBranch.bitcoinSerialize();
60 }
61
62 @Override
63 public byte[] buildFromTxHashes(
64 BtcBlock blockWithHeaderOnly,
65 List<String> txHashesString) {
66 List<Sha256Hash> txHashes = txHashesString.stream().map(Sha256Hash::wrap).collect(Collectors.toList());
67
68 PartialMerkleTree bitcoinMergedMiningMerkleBranch = getBitcoinMergedMerkleBranch(txHashes, blockWithHeaderOnly.getParams());
69
70 return bitcoinMergedMiningMerkleBranch.bitcoinSerialize();
71 }
72
73 @Override
74 public byte[] buildFromBlock(BtcBlock bitcoinMergedMiningBlock) {
75 List<Sha256Hash> txHashes = bitcoinMergedMiningBlock.getTransactions().stream()
76 .map(BtcTransaction::getHash)
77 .collect(Collectors.toList());
78
79 PartialMerkleTree bitcoinMergedMiningMerkleBranch = getBitcoinMergedMerkleBranch(txHashes, bitcoinMergedMiningBlock.getParams());
80
81 return bitcoinMergedMiningMerkleBranch.bitcoinSerialize();
82 }
83
84 /**
85 * getBitcoinMergedMerkleBranch returns the Partial Merkle Branch needed to validate that the coinbase tx
86 * is part of the Merkle Tree.
87 *
88 * @param txHashes the bitcoin txs that were included in a block.
89 * @return A Partial Merkle Branch in which you can validate the coinbase tx.
90 */
91 private static PartialMerkleTree getBitcoinMergedMerkleBranch(List<Sha256Hash> txHashes, NetworkParameters params) {
92 /*
93 We need to convert the txs to a bitvector to choose which ones
94 will be included in the Partial Merkle Tree.
95
96 We need txs.size() / 8 bytes to represent this vector.
97 The coinbase tx is the first one of the txs so we set the first bit to 1.
98 */
99 byte[] bitvector = new byte[(txHashes.size() + 7) / 8];
100 Utils.setBitLE(bitvector, 0);
101 return PartialMerkleTree.buildFromLeaves(params, bitvector, txHashes);
102 }
103 }