// Based on CPartialMerkleTree::TraverseAndBuild in Neoscoin Core. private static void traverseAndBuild( int height, int pos, List<Sha256Hash> allLeafHashes, byte[] includeBits, List<Boolean> matchedChildBits, List<Sha256Hash> resultHashes) { boolean parentOfMatch = false; // Is this node a parent of at least one matched hash? for (int p = pos << height; p < (pos + 1) << height && p < allLeafHashes.size(); p++) { if (Utils.checkBitLE(includeBits, p)) { parentOfMatch = true; break; } } // Store as a flag bit. matchedChildBits.add(parentOfMatch); if (height == 0 || !parentOfMatch) { // If at height 0, or nothing interesting below, store hash and stop. resultHashes.add(calcHash(height, pos, allLeafHashes)); } else { // Otherwise descend into the subtrees. int h = height - 1; int p = pos * 2; traverseAndBuild(h, p, allLeafHashes, includeBits, matchedChildBits, resultHashes); if (p + 1 < getTreeWidth(allLeafHashes.size(), h)) traverseAndBuild(h, p + 1, allLeafHashes, includeBits, matchedChildBits, resultHashes); } }
/** * Calculates a PMT given the list of leaf hashes and which leaves need to be included. The * relevant interior hashes are calculated and a new PMT returned. */ public static PartialMerkleTree buildFromLeaves( NetworkParameters params, byte[] includeBits, List<Sha256Hash> allLeafHashes) { // Calculate height of the tree. int height = 0; while (getTreeWidth(allLeafHashes.size(), height) > 1) height++; List<Boolean> bitList = new ArrayList<Boolean>(); List<Sha256Hash> hashes = new ArrayList<Sha256Hash>(); traverseAndBuild(height, 0, allLeafHashes, includeBits, bitList, hashes); byte[] bits = new byte[(int) Math.ceil(bitList.size() / 8.0)]; for (int i = 0; i < bitList.size(); i++) if (bitList.get(i)) Utils.setBitLE(bits, i); return new PartialMerkleTree(params, bits, hashes, allLeafHashes.size()); }