区块链JAVA描述版

2018-01-21  本文已影响0人  钱佳

不知不觉,又到了周末,已经很久没有写东西了,最近看了很多关于区块链的东西,但是简易的入门的很少,于是,我想着写一篇能让小白快速理解最基础的代码。

区块链概述

网上有很多关于这方面的文章和历史,这里有几个问题简单描述一下:
比特币是一个分布式记账系统,既然是记账,那么数据记在哪儿呢?答案是,记在千千万万个网络的节点上。

分布式记账,要明白几个问题:

一致性的问题?

多种原因可能造成不一致,比如

  1. 每台机器的算力是不一样的,计算有快有慢
  2. 当我和你都收到一笔交易A的时候,我要记这一笔账,你也要记,一切顺利的情况下,我们都记成功了,账本也都是一致的结果,那么如果由于网络问题,你没收到这一笔交易,怎么办?

区块链系统是这样处理的,全网所有的机器都会有一个确认过程,这个确认的过程就是校验交易合法的过程,你遗失了这一笔交易A,最后你算出来的区块和别人不一样,你就白白付出了努力,结果不被认可!

共同造假的问题?

比特币可不可能有造假的问题?当然有,当全网参与记账的节点有51%参与造假,记账就是不对的,当前比特币就有这样的算力中心化的问题。

账记在哪儿?过程怎样?

用户提交一笔交易到网络,网络各个矿工节点(参与记账的)收到了这一笔交易,不会立即记账,而是把这笔交易标记到下一个区块,当准备好出新的区块的时候,矿工需要先算一道题算出一个值,这个值是表示你经过千辛万苦参与了这一次记账,然后把区块信息(包含交易信息,上一个区块的hash,proof算出的答案),提交到网络,所有节点的矿工发现来了一个新的区块,立即停下算题的脚步,看一下这个区块是不是工作在最长链,如果是,校验一下,如果成功,则确认。

proof瞎写会怎样?

接着上面的问题说,如果我没有算这个题,直接瞎写一个答案,提交出去,别的矿工看了,校验了一把,发现你是扯淡的,你算出来的这个区块就丢掉,永远不会被确认。

代码实现:

扯淡了那么久,还是开始写一段代码,更直观。

Block定义
package com.xingchuan.study.blockchain.domain;

import java.util.Set;

/**
 * @author xingchuan.qxc
 * @since 2018/1/20
 */
public class Block {

    /**
     * 区块的序号
     */
    private Long index;

    /**
     * 区块产生的时间
     */
    private Long timestamp;

    /**
     * 区块对应哪些交易
     */
    private Set<Transaction> transactions;

    /**
     * 工作证明
     */
    private Long proof;

    /**
     * 上一个区块的hash
     */
    private String previousHash;

    public Long getIndex() {
        return index;
    }

    public void setIndex(Long index) {
        this.index = index;
    }

    public Long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }

    public Set<Transaction> getTransactions() {
        return transactions;
    }

    public void setTransactions(Set<Transaction> transactions) {
        this.transactions = transactions;
    }

    public Long getProof() {
        return proof;
    }

    public void setProof(Long proof) {
        this.proof = proof;
    }

    public String getPreviousHash() {
        return previousHash;
    }

    public void setPreviousHash(String previousHash) {
        this.previousHash = previousHash;
    }

    @Override
    public String toString() {
        return "{\"Block\":{"
            + "                        \"index\":\"" + index + "\""
            + ",                         \"timestamp\":\"" + timestamp + "\""
            + ",                         \"transactions\":" + transactions
            + ",                         \"proof\":\"" + proof + "\""
            + ",                         \"previousHash\":\"" + previousHash + "\""
            + "}}";
    }
}

Transaction定义
/**
 * @author xingchuan.qxc
 * @since 2018/1/20
 */
public class Transaction {

    /**
     * 发送人
     */
    private String sender;

    /**
     * 接收人
     */
    private String recipient;

    /**
     * 金额
     */
    private long amount;

    public String getSender() {
        return sender;
    }

    public void setSender(String sender) {
        this.sender = sender;
    }

    public String getRecipient() {
        return recipient;
    }

    public void setRecipient(String recipient) {
        this.recipient = recipient;
    }

    public long getAmount() {
        return amount;
    }

    public void setAmount(long amount) {
        this.amount = amount;
    }

    @Override
    public String toString() {
        return "{\"Transaction\":{"
            + "                        \"sender\":\"" + sender + "\""
            + ",                         \"recipient\":\"" + recipient + "\""
            + ",                         \"amount\":\"" + amount + "\""
            + "}}";
    }
}

Blockchain定义

/**
 * @author xingchuan.qxc
 * @since 2018/1/20
 */
public class Blockchain {

    /**
     * Block 链
     */
    private List<Block> blockchain = new LinkedList<>();

    /**
     * 待生成Block的交易
     */
    private Set<Transaction> transactions = new HashSet<>();

    /**
     * 初始化的时候,创建genesis block
     * @throws NoSuchAlgorithmException
     */
    public Blockchain() throws NoSuchAlgorithmException {
        //genesis block,真实场景下,应该是同步区块链的最长链最后一个区块
        newBlock(720L);
    }

    /**
     * 挖矿产生新的区块
     * @throws NoSuchAlgorithmException
     */
    public void mine() throws NoSuchAlgorithmException {
        Block lastBlock = blockchain.get(blockchain.size() - 1);
        Long lastProof = lastBlock.getProof();
        Long proof = proofOfWork(lastProof);
        newTransaction("0", "mineNode", 1L);
        newBlock(proof);

    }

    /**
     * 计算工作证明
     * @param lastProof
     * @return
     * @throws NoSuchAlgorithmException
     */
    public Long proofOfWork(Long lastProof) throws NoSuchAlgorithmException {
        Long proof = 0L;

        while (!validProof(lastProof, proof)) {
            proof++;
        }
        return proof;
    }

    /**
     * 算题,这里定义为,直到算出来的值以0000开头,才算正确答案
     * @param lastProof
     * @param proof
     * @return
     * @throws NoSuchAlgorithmException
     */
    private boolean validProof(Long lastProof, Long proof) throws NoSuchAlgorithmException {
        String guess = "" + lastProof + proof;
        String guessHash = hash(guess);
        return guessHash.startsWith("0000");
    }

    /**
     * 新建一个区块
     * @param proof
     * @return
     * @throws NoSuchAlgorithmException
     */
    public Block newBlock(Long proof) throws NoSuchAlgorithmException {
        Set<Transaction> transactions = new HashSet<>();
        transactions.addAll(this.transactions);
        int index = blockchain.size() - 1;
        Block lastBlock = null;
        if (index >= 0) {
            lastBlock = blockchain.get(index);
        }
        if (lastBlock == null) {
            lastBlock = new Block();
        }
        Block block = new Block();
        block.setIndex(Long.valueOf(blockchain.size() + 1));
        block.setTimestamp(System.currentTimeMillis());
        block.setTransactions(transactions);
        block.setProof(proof);
        block.setPreviousHash(hash(lastBlock.toString()));
        blockchain.add(block);
        this.transactions.clear();
        return block;
    }

    /**
     * 提交一笔新的交易
     * @param sender
     * @param recipient
     * @param amount
     * @return
     */
    public long newTransaction(String sender, String recipient, Long amount) {
        Transaction transaction = new Transaction();
        transaction.setSender(sender);
        transaction.setRecipient(recipient);
        transaction.setAmount(amount);
        this.transactions.add(transaction);

        int lastBlockIndex = blockchain.size() - 1;
        if (lastBlockIndex >= 0) {
            Block block = blockchain.get(lastBlockIndex);
            return block.getIndex() + 1;
        }
        return 0;
    }

    /**
     * SHA-512 算工作量证明
     * @param value
     * @return
     * @throws NoSuchAlgorithmException
     */
    private static String hash(String value) throws NoSuchAlgorithmException {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
        messageDigest.update(value.getBytes());
        return bytesToHexString(messageDigest.digest());
    }

    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    public List<Block> getBlockchain() {
        return blockchain;
    }

    public Set<Transaction> getTransactions() {
        return transactions;
    }
}

测试代码

/**
 * @author xingchuan.qxc
 * @since 2018/1/20
 */
public class TestBlockChain {

    public static void main(String[] args) throws Exception {

        //初始化
        Blockchain blockchain = new Blockchain();

        //提交一笔交易
        blockchain.newTransaction("xingchuan", "shine", 7201L);

        //挖矿记录这一笔交易
        blockchain.mine();

        List<Block> blockList = blockchain.getBlockchain();
        blockList.forEach(block->{
            System.out.println(block);
        });

        Set<Transaction> transactions = blockchain.getTransactions();
        for (Transaction transaction : transactions) {
            System.out.println(transaction);
        }

    }
}

运行结果:

测试运行结果
上一篇下一篇

猜你喜欢

热点阅读