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 }