Java手写简单Merkle树

Java手写Merkle树代码

java 复制代码
package com.blockchain.qgy.component;

import com.blockchain.qgy.model.MerkleTreeNode;
import com.blockchain.qgy.util.SHAUtil;

import java.util.*;

public class MerkleTree<T> {
    //merkle树
    private List<MerkleTreeNode<T>> list;
    //根节点
    private MerkleTreeNode<T> root;

    public MerkleTree(List<T> nodes){
        createMerkleTree(nodes);
    }

    /**
     * function 初始化merkle树
     * @param nodes: 数据集合
     */
    private void createMerkleTree(List<T> nodes) {
        //判断入参
        if (Objects.isNull(nodes) || nodes.size() == 0) return;

        list = new ArrayList<>();

        //创建叶子节点
        List<MerkleTreeNode<T>> leafList = createLeafList(nodes);
        list.addAll(leafList);

        //创建父级节点
        List<MerkleTreeNode<T>> parents = new ArrayList<>(leafList);
        //循环创建直到找到根节点
        do {
            List<MerkleTreeNode<T>> temp = new ArrayList<>(parents);
            temp = createParentList(temp);
            parents = temp;
            list.addAll(parents);
        }while (parents.size() > 1);

        root = parents.get(0);
    }

    /**
     * function 初始化父亲节点
     * @param leafList:叶子节点
     * @return 父节点
     */
    private List<MerkleTreeNode<T>> createParentList(List<MerkleTreeNode<T>> leafList) {
        //判断入参
        if (Objects.isNull(leafList) || leafList.size() == 0) return new ArrayList<>();

        List<MerkleTreeNode<T>> parents = new ArrayList<>();

        int length = leafList.size();
        for(int i = 0;i < length - 1; i += 2){
            MerkleTreeNode<T> parent = createParentNode(leafList.get(i),leafList.get(i+1));
            parents.add(parent);
        }

        //当节点数为奇数时,单独进行处理
        if ((length & 1) == 1) {
            MerkleTreeNode<T> parent = createParentNode(leafList.get(length - 1),null);
            parents.add(parent);
        }

        return parents;
    }

    /**
     * function 生成一个父节点
     * @param left:左节点
     * @param right:右节点
     * @return 父节点
     */
    private MerkleTreeNode<T> createParentNode(MerkleTreeNode<T> left, MerkleTreeNode<T> right) {
        MerkleTreeNode<T> parent = new MerkleTreeNode<>();

        parent.setLeft(left);
        parent.setRight(right);

        String hash = left.getHash();
        if(!Objects.isNull(parent.getRight())) {
            hash = SHAUtil.sha256BasedHutool(hash.concat(parent.getRight().getHash()));
        }
        parent.setHash(hash);
        parent.setName("无人签名");
        parent.setData((T) new Object());
        return parent;
    }

    /**
     * function 初始化叶子节点
     * @param nodes:数据集合
     * @return merkle的叶子节点
     */
    private List<MerkleTreeNode<T>> createLeafList(List<T> nodes) {
        //判断入参
        if (Objects.isNull(nodes) || nodes.size() == 0) return new ArrayList<>();

        List<MerkleTreeNode<T>> leafList = new ArrayList<>();

        for(T curr : nodes) {
            MerkleTreeNode<T> node = new MerkleTreeNode<>(curr);
            leafList.add(node);
        }

        return leafList;
    }

    public void printfTree() {
        Collections.reverse(list);
        MerkleTreeNode<T> root = list.get(0);
        Queue<MerkleTreeNode<T>> queue = new LinkedList<MerkleTreeNode<T>>(){
  
  {
            offer(root);
        }};
        printfTree(queue,1);
    }

    public void printfTree(Queue<MerkleTreeNode<T>> queue,Integer floor) {
        Queue<MerkleTreeNode<T>> currQueue = new LinkedList<>();
        System.out.println("第"+floor+"层--------------------------------------------------------------------------------------------------------------------------");
        while (!queue.isEmpty()) {
            MerkleTreeNode<T> poll = queue.poll();
            System.out.println(poll.toString());
            if(!Objects.isNull(poll.getLeft())) currQueue.offer(poll.getLeft());
            if(!Objects.isNull(poll.getRight())) currQueue.offer(poll.getRight());
        }
        if (!currQueue.isEmpty()) printfTree(currQueue,floor+1);
    }

    public List<MerkleTreeNode<T>> getList() {
        return list;
    }

    public MerkleTreeNode<T> getRoot() {
        return root;
    }

    public void setList(List<MerkleTreeNode<T>> list) {
        this.list = list;
    }

    public void setRoot(MerkleTreeNode<T> root) {
        this.root = root;
    }


}
java 复制代码
package com.blockchain.qgy.model;

import com.blockchain.qgy.util.SHAUtil;

public class MerkleTreeNode<T> {
    //左节点
    private MerkleTreeNode<T> left;
    //右节点
    private MerkleTreeNode<T> right;
    //区块数据
    private T data;
    //节点hash值
    private String hash;
    //数字签名
    private String name;

    public MerkleTreeNode() {

    }

    public MerkleTreeNode(T data) {
        this.data = data;
        this.hash = SHAUtil.sha256BasedHutool(data.toString());
        this.name = "无人签名";
    }

    public MerkleTreeNode(T data, String name){
        this.data = data;
        this.hash = SHAUtil.sha256BasedHutool(data.toString());
        this.name = name;
    }

    public MerkleTreeNode<T> getLeft() {
        return left;
    }

    public void setLeft(MerkleTreeNode<T> left) {
        this.left = left;
    }

    public MerkleTreeNode<T> getRight() {
        return right;
    }

    public void setRight(MerkleTreeNode<T> right) {
        this.right = right;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getHash() {
        return hash;
    }

    public void setHash(String hash) {
        this.hash = hash;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return  "MerkleTreeNode:\n" +
                "name:" + name + ";\n" +
                "data:" + data + ";\n" +
                "------------\n";
    }
}

注意:这里用了SHAUtil工具类,该部分代码链接如下:

SHAUtil代码

测试代码

java 复制代码
package com.blockchain.qgy.test;

import com.blockchain.qgy.component.MerkleTree;
import com.blockchain.qgy.model.MerkleTreeNode;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.List;

public class MerkleTreeTest {

    @Test
    public void Test(){
        List<String> contents = Arrays.asList("星","极","天","下","第","一");
        MerkleTree<String> stringMerkleTree = new MerkleTree<>(contents);
        stringMerkleTree.printfTree();
        MerkleTreeNode<String> root = stringMerkleTree.getRoot();
        System.out.println("root:"+root);
        System.out.println("hash:"+root.getHash());
    }
}

结果:

"C:\Program Files\Java\jdk1.8.0_261\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\idea\IntelliJ IDEA 2020.2.1\lib\idea_rt.jar=55223:D:\idea\IntelliJ IDEA 2020.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\idea\IntelliJ IDEA 2020.2.1\lib\idea_rt.jar;D:\idea\IntelliJ IDEA 2020.2.1\plugins\testng\lib\testng-rt.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_261\jre\lib\rt.jar;D:\项目\区块链\target\classes;C:\Users\86153\Desktop\java架包\org\testng\testng\6.8.7\testng-6.8.7.jar;C:\Users\86153\Desktop\java架包\junit\junit\4.10\junit-4.10.jar;C:\Users\86153\Desktop\java架包\org\hamcrest\hamcrest-core\1.1\hamcrest-core-1.1.jar;C:\Users\86153\Desktop\java架包\org\beanshell\bsh\2.0b4\bsh-2.0b4.jar;C:\Users\86153\Desktop\java架包\com\beust\jcommander\1.27\jcommander-1.27.jar;C:\Users\86153\Desktop\java架包\org\yaml\snakeyaml\1.12\snakeyaml-1.12.jar;C:\Users\86153\Desktop\java架包\org\mockito\mockito-all\1.9.5\mockito-all-1.9.5.jar;C:\Users\86153\Desktop\java架包\com\xiaoleilu\hutool-all\3.0.9\hutool-all-3.0.9.jar;C:\Users\86153\Desktop\java架包\com\google\crypto\tink\tink\1.2.0\tink-1.2.0.jar;C:\Users\86153\Desktop\java架包\com\amazonaws\aws-java-sdk-core\1.11.166\aws-java-sdk-core-1.11.166.jar;C:\Users\86153\Desktop\java架包\software\amazon\ion\ion-java\1.0.2\ion-java-1.0.2.jar;C:\Users\86153\Desktop\java架包\com\fasterxml\jackson\dataformat\jackson-dataformat-cbor\2.6.7\jackson-dataformat-cbor-2.6.7.jar;C:\Users\86153\Desktop\java架包\joda-time\joda-time\2.8.1\joda-time-2.8.1.jar;C:\Users\86153\Desktop\java架包\com\amazonaws\aws-java-sdk-kms\1.11.166\aws-java-sdk-kms-1.11.166.jar;C:\Users\86153\Desktop\java架包\com\amazonaws\jmespath-java\1.11.166\jmespath-java-1.11.166.jar;C:\Users\86153\Desktop\java架包\com\fasterxml\jackson\core\jackson-databind\2.6.7.1\jackson-databind-2.6.7.1.jar;C:\Users\86153\Desktop\java架包\com\fasterxml\jackson\core\jackson-annotations\2.6.0\jackson-annotations-2.6.0.jar;C:\Users\86153\Desktop\java架包\com\google\api-client\google-api-client\1.22.0\google-api-client-1.22.0.jar;C:\Users\86153\Desktop\java架包\com\google\oauth-client\google-oauth-client\1.22.0\google-oauth-client-1.22.0.jar;C:\Users\86153\Desktop\java架包\com\google\http-client\google-http-client\1.22.0\google-http-client-1.22.0.jar;C:\Users\86153\Desktop\java架包\org\apache\httpcomponents\httpclient\4.0.1\httpclient-4.0.1.jar;C:\Users\86153\Desktop\java架包\org\apache\httpcomponents\httpcore\4.0.1\httpcore-4.0.1.jar;C:\Users\86153\Desktop\java架包\commons-logging\commons-logging\1.1.1\commons-logging-1.1.1.jar;C:\Users\86153\Desktop\java架包\commons-codec\commons-codec\1.3\commons-codec-1.3.jar;C:\Users\86153\Desktop\java架包\com\google\http-client\google-http-client-jackson2\1.22.0\google-http-client-jackson2-1.22.0.jar;C:\Users\86153\Desktop\java架包\com\fasterxml\jackson\core\jackson-core\2.1.3\jackson-core-2.1.3.jar;C:\Users\86153\Desktop\java架包\com\google\apis\google-api-services-cloudkms\v1-rev9-1.22.0\google-api-services-cloudkms-v1-rev9-1.22.0.jar;C:\Users\86153\Desktop\java架包\com\google\guava\guava\25.0-jre\guava-25.0-jre.jar;C:\Users\86153\Desktop\java架包\com\google\code\findbugs\jsr305\1.3.9\jsr305-1.3.9.jar;C:\Users\86153\Desktop\java架包\org\checkerframework\checker-compat-qual\2.0.0\checker-compat-qual-2.0.0.jar;C:\Users\86153\Desktop\java架包\com\google\errorprone\error_prone_annotations\2.1.3\error_prone_annotations-2.1.3.jar;C:\Users\86153\Desktop\java架包\com\google\j2objc\j2objc-annotations\1.1\j2objc-annotations-1.1.jar;C:\Users\86153\Desktop\java架包\org\codehaus\mojo\animal-sniffer-annotations\1.14\animal-sniffer-annotations-1.14.jar;C:\Users\86153\Desktop\java架包\com\google\auto\service\auto-service\1.0-rc4\auto-service-1.0-rc4.jar;C:\Users\86153\Desktop\java架包\com\google\auto\auto-common\0.8\auto-common-0.8.jar;C:\Users\86153\Desktop\java架包\com\google\protobuf\protobuf-java\3.3.0\protobuf-java-3.3.0.jar;C:\Users\86153\Desktop\java架包\org\json\json\20170516\json-20170516.jar;D:\idea\IntelliJ IDEA 2020.2.1\plugins\testng\lib\jcommander-1.27.jar" com.intellij.rt.testng.RemoteTestNGStarter -usedefaultlisteners false -socket55222 @w@C:\Users\86153\AppData\Local\Temp\idea_working_dirs_testng.tmp -temp C:\Users\86153\AppData\Local\Temp\idea_testng.tmp

[TestNG] Running:

C:\Users\86153\AppData\Local\JetBrains\IntelliJIdea2020.2\temp-testng-customsuite.xml

第1层------------------------------------------------------------------------------------------------------------------

MerkleTreeNode:

name:无人签名;

data:java.lang.Object@b684286;


第2层------------------------------------------------------------------------------------------------------------------

MerkleTreeNode:

name:无人签名;

data:java.lang.Object@880ec60;


MerkleTreeNode:

name:无人签名;

data:java.lang.Object@3f3afe78;


第3层------------------------------------------------------------------------------------------------------------------

MerkleTreeNode:

name:无人签名;

data:java.lang.Object@7f63425a;


MerkleTreeNode:

name:无人签名;

data:java.lang.Object@36d64342;


MerkleTreeNode:

name:无人签名;

data:java.lang.Object@39ba5a14;


第4层------------------------------------------------------------------------------------------------------------------

MerkleTreeNode:

name:无人签名;

data:星;


MerkleTreeNode:

name:无人签名;

data:极;


MerkleTreeNode:

name:无人签名;

data:天;


MerkleTreeNode:

name:无人签名;

data:下;


MerkleTreeNode:

name:无人签名;

data:第;


MerkleTreeNode:

name:无人签名;

data:一;


root:MerkleTreeNode:

name:无人签名;

data:java.lang.Object@b684286;


hash:4e8da83f3ee3cb2ddb2d5dec5724a0c01bb4f6f48d2f7c3dd46f51158b26b5f4

===============================================

Default Suite

Total tests run: 1, Failures: 0, Skips: 0

===============================================

Process finished with exit code 0

相关推荐
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
Miketutu2 小时前
Spring MVC消息转换器
java·spring
LUCIAZZZ3 小时前
简单的SQL语句的快速复习
java·数据库·sql
komo莫莫da3 小时前
寒假刷题Day19
java·开发语言
S-X-S4 小时前
算法总结-数组/字符串
java·数据结构·算法
linwq84 小时前
设计模式学习(二)
java·学习·设计模式
桦说编程5 小时前
CompletableFuture 超时功能有大坑!使用不当直接生产事故!
java·性能优化·函数式编程·并发编程
@_@哆啦A梦5 小时前
Redis 基础命令
java·数据库·redis
字节全栈_rJF6 小时前
性能测试 —— Tomcat监控与调优:status页监控_tomcat 自带监控
java·tomcat