基于Java 实现区块链的工作量证明机制

129 阅读2分钟

基于Java 实现区块链的工作量证明机制

1. 区块加入随机值

/**
 * 区块链 里边存放的数据是:
 * data 数据
 * preHash 上一个区块的hash值
 * hash 自己的 hash值 它是由存储在区块链的信息 计算出来的(data + 之前区块的哈希值) ,采用 sha256 算法
 */
public class Block {

    private Object data;

    private String  preHash;

    private String  hash;

    // 初始随机值
    private Long nonce;

    public Block(Object data, String preHash) {
        this.data = data;
        this.preHash = preHash;
        this.hash = this.computeHash();
        this.nonce = 1L;
    }

    public Object getData() {
        return data;
    }

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

    public String getPreHash() {
        return preHash;
    }

    public void setPreHash(String preHash) {
        this.preHash = preHash;
    }

    public String getHash() {
        return hash;
    }

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

    public Long getNonce() {
        return nonce;
    }

    public void setNonce(Long nonce) {
        this.nonce = nonce;
    }

    public String computeHash() {
        // 要加入随机值 nonce
        return new Encrypt().SHA256(this.data + this.preHash + this.nonce);
    }

    // 开头前n 位为0的 hash值
    public String  getAnswer(Integer difficulty) {
        String answer = "";
        for (int i = 0; i < difficulty; i++) {
            answer +="0";
        }
        return answer;

    }
    // 计算符合区块链难度要求的hash 这个过程 俗称 挖矿
    public void mine(Integer difficulty) {
        while (true) {
            this.hash = this.computeHash();
            if (! this.hash.substring(0,difficulty).equals(this.getAnswer(difficulty))) {
                // nonce ++ 才会得到不同的hash值
                this.nonce ++ ;
                this.hash =this.computeHash();
            } else {
                break;
            }
        }
        System.out.println("挖矿结束:"+ this.hash);
    }

    @Override
    public String toString() {
        return "Block{" +
                "data=" + data +
                ", preHash='" + preHash + '\'' +
                ", hash='" + hash + '\'' +
                ", nonce=" + nonce +
                '}';
    }

    public static void main(String[] args) {
        Block block = new Block("转账10元","1234");
        System.out.println(block);

    }
}

2. 链对象添加 工作量难度系数

import java.util.ArrayList;
import java.util.List;

/**
 * 区块的链
 */
public class Chain {

    private List<Block> chain = new ArrayList<>();

    // 工作量难度
    private Integer difficulty;

    public Chain() {
        chain.add(bigBang());
        this.difficulty = 5;
    }

    public Chain(List<Block> chain) {
        chain.add(bigBang());
        this.chain.addAll(chain);
    }

    /**
     * 每个区块都会生成一个祖先区块
     * @return
     */
    public Block bigBang() {
        // 创建祖先节点 hash为空
        return new Block("祖先","");
    }

    /**
     * 获取最后一个区块的信息
     * @return
     */
    public Block getLatestBlock() {
        return getChain().get(this.chain.size()-1);
    }
    /**
     * 添加区块到区块链上
     * 找到最近一个block的hash
     * 这个hash就是新区块的preHash
     */
    public void addBlockToChain(Block newBlock) {
        newBlock.setPreHash(this.getLatestBlock().computeHash());
        newBlock.setHash(newBlock.computeHash());
        // 比特币 控制 每十分钟出一个区块了 就是通过 ProofOfWork 工作机制
        // 这个hash 需要满足一个区块链设置的条件
        newBlock.mine(this.difficulty);
        this.chain.add(newBlock);
    }

    public List<Block> getChain() {
        return chain;
    }

    public void setChain(List<Block> chain) {
        this.chain = chain;
    }

    /**
     * 验证这个当前的区块链是否合法
     * 当前的区块是否被篡改
     *  我们要验证区块的preHash是否等于previous区块hash
     */
    public Boolean validateBlockChain() {
        // 创始区块的校验
        if (this.chain.size() == 1) {
            // 比较创始区块的hash值
            if (! this.chain.get(0).getHash().equalsIgnoreCase(this.chain.get(0).computeHash())) {
                return false;
            }
           return true;
        } else {
            // this.chain[1] 是第二个区块
            // 我们从第二个区块开始验证
            // 验证到最后一个区块  this.chain.size() -1
            for (int i = 1; i <= this.chain.size() -1; i++) {
                Block blockValidate = this.chain.get(i);
                // 验证当前数据是否被篡改
                if (!blockValidate.getHash().equalsIgnoreCase(blockValidate.computeHash())) {
                    System.out.println("数据被篡改!");
                    return false;
                }
                // 验证区块的previousHash 是否等于 previous区块的hash
                Block previousBlock = this.chain.get(i-1);
                //
                if (!blockValidate.getPreHash().equalsIgnoreCase(previousBlock.getHash())) {
                    System.out.println("前后区块链接断裂!");
                    return  false;
                }
            }
            return  true;
        }
    }

    @Override
    public String toString() {
        return "Chain{" +
                "chain=" + chain +
                '}';
    }

    public static void main(String[] args) {
        Chain chain = new Chain();
//        System.out.println(chain.validateBlockChain());
        Block block1 = new Block("转账10元","1234");
        chain.addBlockToChain(block1);
        Block block2 = new Block("转账20元","1234");
        chain.addBlockToChain(block2);
        System.out.println(chain);

//        System.out.println(chain.validateBlockChain());
//        // 篡改区块链上的数据
        chain.getChain().get(1).setData("转账30元");
//        System.out.println(chain.validateBlockChain());
        // 篡改区块链的hash值
//        chain.getChain().get(1).setHash(chain.getChain().get(1).computeHash());
        chain.getChain().get(1).mine(5);
        System.out.println(chain);
        System.out.println(chain.validateBlockChain());

    }
}