Coverage Summary for Class: MerkleBranch (co.rsk.peg.bitcoin)
Class |
Class, %
|
Method, %
|
Line, %
|
MerkleBranch |
0%
(0/1)
|
0%
(0/5)
|
0%
(0/20)
|
1 package co.rsk.peg.bitcoin;
2
3 import co.rsk.bitcoinj.core.BtcBlock;
4 import co.rsk.bitcoinj.core.Sha256Hash;
5 import co.rsk.peg.utils.MerkleTreeUtils;
6 import org.ethereum.util.Utils;
7
8 import java.util.Collections;
9 import java.util.List;
10
11 /**
12 * Represents a branch of a merkle tree. Can be used
13 * to validate that a certain transaction belongs
14 * to a certain block.
15 *
16 * IMPORTANT: this class can only be used to validate
17 * an existing merkle branch against a <block, transaction> pair.
18 * It cannot be used to generate a merkle branch from a complete
19 * block and a single transaction, since there's no use case
20 * for it.
21 *
22 * @author Ariel Mendelzon
23 */
24 public class MerkleBranch {
25 private final List<Sha256Hash> hashes;
26 private final int path;
27
28 public MerkleBranch(List<Sha256Hash> hashes, int path) {
29 this.hashes = Collections.unmodifiableList(hashes);
30 this.path = path;
31
32 //We validate that the number of hashes is uint8 as described in https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki
33 if (hashes.size() > 32) {
34 throw new IllegalArgumentException("The number of hashes can't be bigger than 255");
35 }
36 // We validate here that there are no more bits in the
37 // path than those needed to reduce the branch to the
38 // merkle root. That is, that the number of significant
39 // bits is lower or equal to the number of hashes
40 if (Utils.significantBitCount(path) > hashes.size()) {
41 throw new IllegalArgumentException("The number of significant bits must be lower or equal to the number of hashes");
42 }
43 }
44
45 public List<Sha256Hash> getHashes() {
46 return hashes;
47 }
48
49 public int getPath() {
50 return path;
51 }
52
53 /**
54 * Returns true if and only if this
55 * merkle branch successfully proves
56 * that tx hash is included in block.
57 *
58 * @param txHash The transaction hash
59 * @param block The BTC block
60 * @return Whether this branch proves inclusion of tx in block.
61 */
62 public boolean proves(Sha256Hash txHash, BtcBlock block) {
63 return block.getMerkleRoot().equals(reduceFrom(txHash));
64 }
65
66 /**
67 * Given a transaction hash, this method traverses the path, calculating
68 * the intermediate hashes and ultimately arriving at
69 * the merkle root.
70 *
71 * @param txHash The transaction hash
72 * @return The merkle root obtained from the traversal
73 */
74 public Sha256Hash reduceFrom(Sha256Hash txHash) {
75 Sha256Hash current = txHash;
76 int index = 0;
77 while (index < hashes.size()) {
78 boolean currentRight = ((path >> index) & 1) == 1;
79 if (currentRight) {
80 current = MerkleTreeUtils.combineLeftRight(hashes.get(index), current);
81 } else {
82 current = MerkleTreeUtils.combineLeftRight(current, hashes.get(index));
83 }
84 index++;
85 }
86 return current;
87 }
88 }