Merkle Tree
- 葉子節點爲奇數時,複製最後一個;而後由全部葉子節點構造一個滿二叉樹
- List 第 0 個存放空,root 放在第 1 個。則第 i 個葉子節點在 list 中的下標爲 k = i + list.size() / 2; 由葉子節點往上須要獲取的節點爲 k % 2 == 0 ? k+1 : k-1,而後 k=k/2 往上遞歸直到 root,即 1。
public class MT {
private static final Logger logger = LoggerFactory.getLogger(MT.class);
List<HashNode> leaves;
List<HashNode> list = new ArrayList<>();
HashNode root;
public MT(List<HashNode> leaves) {
this.leaves = leaves;
list.add(new HashNode("", null, null));
}
public static void main(String[] args) {
List<HashNode> leaves = new ArrayList<>();
for (String h : Arrays.asList("a", "b", "c", "d", "e", "f", "g")) {
leaves.add(new HashNode(h, null, null));
}
MT mt = new MT(leaves);
mt.buildFromLeaves();
logger.info("root:{}, hashNodes:{}", mt.root, mt.list.subList(1, mt.list.size()));
for (int i = 0; i < leaves.size(); i++) {
logger.info("hashes:{}", mt.getHashes(i));
}
List<HashNode> hashes = mt.getHashes(0);
int k = 0;
String calRootHash = leaves.get(k).hash;
for (HashNode h : hashes) {
if (k % 2 == 0) calRootHash = hash(calRootHash, h.hash);
else calRootHash = hash(h.hash, calRootHash);
}
logger.info("calRootHash:{}, rootHash:{}", calRootHash, mt.root.hash);
}
private static String hash(String l, String r) {
return l + "-" + r;
}
private static List<HashNode> fromSubLayer(List<HashNode> subLayer) {
List<HashNode> currentLayer = new ArrayList<>();
for (int i = 0; i < subLayer.size(); i += 2) {
HashNode left = subLayer.get(i);
HashNode right = subLayer.get(i + 1);
currentLayer.add(new HashNode(hash(left.hash, right.hash), left, right));
}
return currentLayer;
}
private List<HashNode> getHashes(int i) {
int k = i + list.size() / 2;
List<HashNode> result = new ArrayList<>();
while (k / 2 >= 1) {
if (k % 2 == 0) result.add(list.get(k + 1));
else result.add(list.get(k - 1));
k = k / 2;
}
return result;
}
private void buildFromLeaves() {
if (leaves.size() % 2 == 1) leaves.add(leaves.get(leaves.size() - 1));
List<HashNode> temp = leaves;
do {
list.addAll(1, temp);
temp = fromSubLayer(temp);
} while (temp.size() > 1);
list.addAll(1, temp);
root = list.get(1);
}
private static class HashNode {
String hash;
HashNode l, r;
public HashNode(String hash, HashNode l, HashNode r) {
this.hash = hash;
this.l = l;
this.r = r;
}
@Override
public String toString() {
return hash;
}
}
}