Java手写简单Merkle树

news/2025/2/2 4:55:14 标签: 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
 


http://www.niftyadmin.cn/n/5839759.html

相关文章

芯片AI深度实战:让verilog不再是 AI 的小众语言

系列文章: 芯片AI深度实战:私有模型deep seek r1,必会ollama-CSDN博客 芯片AI深度实战:自己的AI,必会LangChain-CSDN博客 芯片AI深度实战:给vim装上AI-CSDN博客 芯片AI深度实战:火的编程AI,都在用语法树(AST)-CSDN博客

事务02之锁机制

锁机制 文章目录 锁机制一&#xff1a;MySQL锁的由来与分类1&#xff1a;锁机制的分类 二&#xff1a;共享锁与排他锁1&#xff1a;共享锁(S锁)2&#xff1a;排他锁(X锁)3&#xff1a;锁的释放 二&#xff1a;表级别锁1&#xff1a;元数据锁(了解)2&#xff1a;意向锁3&#xf…

【Linux】Linux C判断两个IPv6地址是否有包含关系

功能说明 要判断两个 IPv6 地址是否具有包含关系&#xff0c;包括前缀的比较&#xff0c;可以通过以下步骤实现&#xff1a; 解析 IPv6 地址和前缀&#xff1a;将两个 IPv6 地址和它们的前缀长度解析为二进制形式。生成掩码&#xff1a;根据前缀长度生成掩码。按位比较&#…

Kafka分区策略实现

引言 Kafka 的分区策略决定了生产者发送的消息会被分配到哪个分区中&#xff0c;合理的分区策略有助于实现负载均衡、提高消息处理效率以及满足特定的业务需求。 轮询策略&#xff08;默认&#xff09; 轮询策略是 Kafka 默认的分区策略&#xff08;当消息没有指定键时&…

Kadane 算法

Kadane 算法 Kadane 算法用于解决最大子数组和问题,即在一个整数数组中找到具有最大和的连续子数组。此算法基于动态规划思想,在一次遍历过程中完成计算。 动态规划思路 核心在于维护两个变量:currentMax 表示当前子数组的最大和;globalMax 保存迄今为止发现的最大子数组…

PPT添加与管理批注的操作指南

​​​ 批注是PPT中一个非常实用的功能&#xff0c;它不仅能帮助我们在演讲和设计过程中记录想法&#xff0c;还能与他人协作时提供有价值的反馈。无论是团队讨论、审稿&#xff0c;还是个人思考&#xff0c;批注的运用都能让我们的PPT更加完善和高效。我会详细介绍如何在PPT中…

实战:利用百度站长平台加速网站收录

本文转自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/33.html 利用百度站长平台加速网站收录是一个实战性很强的过程&#xff0c;以下是一些具体的步骤和策略&#xff1a; 一、了解百度站长平台 百度站长平台是百度为网站管理员提供的一系列工…

Git的安装步骤详解(复杂的安装界面该如何勾选?)

目录 一、下载与安装 1.官网下载git 2、下载完成之后&#xff0c;双击下载好的exe文件进行安装 3、选择Git的安装路径 4、选择在安装 Git 时要包含的组件和功能 5、选择 Git 快捷方式在 Windows 开始菜单中的位置。 6、选择 Git 使用的默认编辑器 7、调整新仓库中初始分…