区块链JAVA描述版

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

区块链概述

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

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

一致性的问题?

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

  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);
        }

    }
}

运行结果:

测试运行结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容