Java实现简单的区块链

区块链可以简单抽象成将一个个区块存放在一个链表中,每新增一个块就把它放置在链表尾端,并通过区块之间信息的传递形成独一无二的hash,来确保区块链的数据未被篡改过。

区块的实现

区块的基本属性有:

  • 当前区块的hash值

  • 前一个区块的hash值

  • 当前区块的数据值

  • 当前块的时间戳

其中,通过对前一区块的hash(若为第一个区块则为0)、当前区块的数据值和当前的时间戳进行加密处理,可以生成一个独一无二的属于当前区块hash值。

public class Block {
    public String hash;//当前块的哈希值
    public String previousHash;//前一个块的哈希值
    private String data;//当前块的数据
    private long timeStamp;//当前块的时间戳

    //初始化区块
    public Block(String data, String previousHash) {
        this.data = data;
        this.previousHash = previousHash;
        this.timeStamp = System.currentTimeMillis();
        this.hash = calculateHash();
    }

    //通过sha256散列算法生成hash值
    public String calculateHash() {
        String calculatedhash = 
            StringUtil.applySha256(previousHash 
                                   +Long.toString(timeStamp) 
                                   +data);
        return calculatedhash;
    }

}

sha256散列算法

之所以选用SHA256是因为它的大小正合适,一方面产生重复hash值的可能性很小,另一方面在区块链实际应用过程中,有可能会产生大量的区块,而使得信息量很大,那么256位的大小就比较恰当了。

public class StringUtil {
    public static String applySha256(String input){
        try {
            //指定使用的加密算法为SHA-256
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            //计算当前输入数据的散列值
            byte[] hash = digest.digest(input.getBytes(StandardCharsets.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);
        }
    }
}

测试

创建一个链表用来存放区块,从而形成区块链。

public class NoobChain {

    public static ArrayList<Block> blockchain = new ArrayList<Block>();

    public static void main(String[] args) {
        //将每一个块添加到区块链中
        //传入块的信息:当前块的数据信息、上一块的hash值
        blockchain.add(new Block("The first block", "0"));
        blockchain.add(new Block("The second block", blockchain.get(blockchain.size() - 1).hash));
        blockchain.add(new Block("The third block", blockchain.get(blockchain.size() - 1).hash));

        //将区块链用整齐的格式打印出来
        String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
        System.out.println(blockchainJson);
    }
}

检验区块链的完整性

检验区块链是否完整,是通过验证当前块和上一块的hash是否正确来实现的。由于区块链的每个节点生成后便不可修改,所以当某一块的hash值发生变化时,则证明其数据等信息被篡改过,区块链不再完整。

     //判断区块链是否有效
    public static Boolean isChainValid() {
        Block currentBlock;
        Block previousBlock;
        //通过检查哈希值来判断是否是一个有效的区块链
        for (int i = 1; i < blockchain.size(); i++) {
            currentBlock = blockchain.get(i);
            previousBlock = blockchain.get(i - 1);
            //比较块中的注册hash和再次计算的hash值是否相同
            if (!currentBlock.hash.equals(currentBlock.calculateHash())) {
                System.out.println("Current Hashes not equal");
                return false;
            }
            //比较前一个块的hash值和当前块的previousHash值是否相同
            if (!previousBlock.hash.equals(currentBlock.previousHash)) {
                System.out.println("Previous Hashes not equal");
                return false;
            }
        }
        return true;
    }

区块链中的任何区块出现改变都会导致hash变化,这个函数返回false,也就证明了区块链无效了。

本文参考:java开发区块链只需150行代码

Java源代码保存在GitHub

猜你喜欢

转载自blog.csdn.net/m0_51561690/article/details/128687066