Java实现区块链 --- 代码篇

首先弄清楚需要哪些信息

自身的hash值,上一个区块的hash值,保存的数据信息,时间戳,随机数。

创建一个Block类

package blockChain;

import java.util.Date;

/**
 * @author WuYongheng
 * @date 2022/10/22
 * @description
 */
public class Block {
    public String hash;
    public String previousHash;
    private String data;
    private long timeStamp;
    private int nonce;

    /**
     * 区块构造函数
     *
     * @param previousHash
     * @param data
     */
    public Block(String data, String previousHash) {
        this.previousHash = previousHash;
        this.data = data;
        this.timeStamp = new Date().getTime();
        this.hash = calculateHash();
    }

    /**
     * 计算区块的hash值,使用SHA256加密算法
     * nonce每加一次,都会调用一次applySha256()方法
     *
     * @return calculateHash
     */
    private String calculateHash() {
        String calculateHash = StringUtil.applySha256(
                previousHash
                        + Long.toString(timeStamp)
                        + data
                        + Integer.toString(nonce)
        );
        return calculateHash;
    }

    /**
     * 通过随机数nonce的递增,不断地尝试,得到符合要求的哈希值,使用SHA256加密
     * 人为制造哈希碰撞的可能性很低,可以认为随机数是唯一的
     *
     * @param difficulty 困难度,表示哈希值的开头有多少个零
     */
    public void mineBlock(int difficulty) {
        String target = StringUtil.getDifficultyString(difficulty);
        while (!hash.substring(0, difficulty).equals(target)) {
            nonce++;
            hash = calculateHash();
        }
        System.out.println("Block Mined!!! : " + hash);
    }

}

创建一个工具类

需要手动添加一下gson的jar包

package blockChain;

import com.google.gson.GsonBuilder;

import java.security.MessageDigest;

/**
 * @author WuYongheng
 * @date 2022/10/22
 * @description 工具类,负责加密,返回‘困难度’个零,解析json数据
 */
public class StringUtil {
    /**
     * for循环的解释:0xff & hash[i]
     *
     * @param input 未加密的字符串
     * @return 加密之后的字符串
     */
    public static String applySha256(String input) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
//            传入需要计算的字符串,把输入变成ascii值
            byte[] hash = digest.digest(input.getBytes("UTF-8"));
            StringBuffer hexString = new StringBuffer();

            for (int i = 0; i < hash.length; i++) {
                String hex = Integer.toHexString(0xff & hash[i]);
                if (hex.length() == 1) {
                    hexString.append('0');
                } 
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 困难度是多少,就返回多少个零
     * 比如 difficulty=6 返回 000000
     * @param difficulty 困难度
     * @return 一个字符串
     */
    public static String getDifficultyString(int difficulty) {
        return new String(new char[difficulty]).replace('\0', '0');
    }

    /**
     * 将数据以json的格式显示
     * @param o
     * @return
     */
    public static String getJson(Object o) {
        return new GsonBuilder().setPrettyPrinting().create().toJson(o);
    }

}

单独解释一下for循环

            for (int i = 0; i < hash.length; i++) {
                String hex = Integer.toHexString(0xff & hash[i]);
                if (hex.length() == 1) {
                    hexString.append('0');
                } 
                hexString.append(hex);
            }

理解:0xff & hash[i] 与 操作  hexString.append('0')  补零操作

有了这两步,就能确保得到一共64位的哈希值,每一位上的数可以转换成4位2进制数,比如a转换成1010,64*4一共256位0和1组成的哈希值。

创建一个测试类

package blockChain;

import java.util.ArrayList;

/**
 * @author WuYongheng
 * @date 2022/10/22
 * @description 测试类
 */
public class TestBlockChain {

    public static ArrayList<Block> blockchain = new ArrayList<Block>();
    // 设置挖矿困难度为5,会体现在哈希值,以5个0开头,困难度越大,计算花的时间越多
    public static int difficulty = 5;

    /**
     * 手动创建3个区块,将区块的内容以json的格式展示
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("Trying to Mine block 1... ");
        // 创世块,前一个区块的哈希值为 0
        addBlock(new Block("Hi im the first block", "0"));

        System.out.println("Trying to Mine block 2... ");
        addBlock(new Block("Yo im the second block", blockchain.get(blockchain.size() - 1).hash));

        System.out.println("Trying to Mine block 3... ");
        addBlock(new Block("Hey im the third block", blockchain.get(blockchain.size() - 1).hash));

        String blockchainJson = StringUtil.getJson(blockchain);
        System.out.println("\nThe block chain: ");
        System.out.println(blockchainJson);

    }

    /**
     * 创建新的区块
     * @param newBlock
     */
    private static void addBlock(Block newBlock) {
        newBlock.mineBlock(difficulty);
        blockchain.add(newBlock);
    }
}

结果

"C:\Program Files\Java\jdk1.8.0_221\bin\java.exe" "-javaagent:D:\devenv\IntelliJ IDEA 2021.1.1\lib\idea_rt.jar=51144:D:\devenv\IntelliJ IDEA 2021.1.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_221\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\rt.jar;D:\code\before\csdncode\out\production\CSDNcode;C:\Users\Administrator\Desktop\学习笔记\老刘\jar包\gson-2.8.2.jar" blockChain.TestBlockChain
Trying to Mine block 1... 
Block Mined!!! : 0000071d5ed7e99267ffbe73df5b01affe62928347bbe4032187f20fac1c8bb0
Trying to Mine block 2... 
Block Mined!!! : 00000015080301d4e8a24786cc9ed85949fc96607d28373e04dfd5dd003a0233
Trying to Mine block 3... 
Block Mined!!! : 0000096564160a2b6758839900780138760fb210044cb8685715646e4b511534

The block chain: 
[
  {
    "hash": "0000071d5ed7e99267ffbe73df5b01affe62928347bbe4032187f20fac1c8bb0",
    "previousHash": "0",
    "data": "Hi im the first block",
    "timeStamp": 1666431244665,
    "nonce": 1214985
  },
  {
    "hash": "00000015080301d4e8a24786cc9ed85949fc96607d28373e04dfd5dd003a0233",
    "previousHash": "0000071d5ed7e99267ffbe73df5b01affe62928347bbe4032187f20fac1c8bb0",
    "data": "Yo im the second block",
    "timeStamp": 1666431246529,
    "nonce": 656899
  },
  {
    "hash": "0000096564160a2b6758839900780138760fb210044cb8685715646e4b511534",
    "previousHash": "00000015080301d4e8a24786cc9ed85949fc96607d28373e04dfd5dd003a0233",
    "data": "Hey im the third block",
    "timeStamp": 1666431247645,
    "nonce": 157564
  }
]

Process finished with exit code 0

使用在线加密工具验证

以第一个区块为例

源码地址

https://gitee.com/ipkiss/csdncode

参考

sunny_ice

猜你喜欢

转载自blog.csdn.net/Ipkiss_Yongheng/article/details/127461808