區(qū)塊鏈JAVA描述版

不知不覺陷虎,又到了周末,已經很久沒有寫東西了杠袱,最近看了很多關于區(qū)塊鏈的東西尚猿,但是簡易的入門的很少,于是楣富,我想著寫一篇能讓小白快速理解最基礎的代碼凿掂。

區(qū)塊鏈概述

網上有很多關于這方面的文章和歷史,這里有幾個問題簡單描述一下:
比特幣是一個分布式記賬系統(tǒng)纹蝴,既然是記賬庄萎,那么數(shù)據(jù)記在哪兒呢?答案是塘安,記在千千萬萬個網絡的節(jié)點上糠涛。

分布式記賬,要明白幾個問題:

一致性的問題兼犯?

多種原因可能造成不一致忍捡,比如

  1. 每臺機器的算力是不一樣的,計算有快有慢
  2. 當我和你都收到一筆交易A的時候切黔,我要記這一筆賬砸脊,你也要記,一切順利的情況下纬霞,我們都記成功了凌埂,賬本也都是一致的結果,那么如果由于網絡問題诗芜,你沒收到這一筆交易侨舆,怎么辦?

區(qū)塊鏈系統(tǒng)是這樣處理的绢陌,全網所有的機器都會有一個確認過程挨下,這個確認的過程就是校驗交易合法的過程,你遺失了這一筆交易A脐湾,最后你算出來的區(qū)塊和別人不一樣臭笆,你就白白付出了努力,結果不被認可!

共同造假的問題愁铺?

比特幣可不可能有造假的問題鹰霍?當然有,當全網參與記賬的節(jié)點有51%參與造假茵乱,記賬就是不對的茂洒,當前比特幣就有這樣的算力中心化的問題。

賬記在哪兒瓶竭?過程怎樣督勺?

用戶提交一筆交易到網絡,網絡各個礦工節(jié)點(參與記賬的)收到了這一筆交易斤贰,不會立即記賬智哀,而是把這筆交易標記到下一個區(qū)塊,當準備好出新的區(qū)塊的時候荧恍,礦工需要先算一道題算出一個值瓷叫,這個值是表示你經過千辛萬苦參與了這一次記賬,然后把區(qū)塊信息(包含交易信息送巡,上一個區(qū)塊的hash摹菠,proof算出的答案),提交到網絡骗爆,所有節(jié)點的礦工發(fā)現(xiàn)來了一個新的區(qū)塊次氨,立即停下算題的腳步,看一下這個區(qū)塊是不是工作在最長鏈淮腾,如果是糟需,校驗一下屉佳,如果成功谷朝,則確認。

proof瞎寫會怎樣武花?

接著上面的問題說圆凰,如果我沒有算這個題,直接瞎寫一個答案体箕,提交出去专钉,別的礦工看了,校驗了一把累铅,發(fā)現(xiàn)你是扯淡的跃须,你算出來的這個區(qū)塊就丟掉,永遠不會被確認娃兽。

代碼實現(xiàn):

扯淡了那么久菇民,還是開始寫一段代碼,更直觀。

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

import java.util.Set;

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

    /**
     * 區(qū)塊的序號
     */
    private Long index;

    /**
     * 區(qū)塊產生的時間
     */
    private Long timestamp;

    /**
     * 區(qū)塊對應哪些交易
     */
    private Set<Transaction> transactions;

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

    /**
     * 上一個區(qū)塊的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 {

    /**
     * 發(fā)送人
     */
    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<>();

    /**
     * 初始化的時候第练,創(chuàng)建genesis block
     * @throws NoSuchAlgorithmException
     */
    public Blockchain() throws NoSuchAlgorithmException {
        //genesis block阔馋,真實場景下,應該是同步區(qū)塊鏈的最長鏈最后一個區(qū)塊
        newBlock(720L);
    }

    /**
     * 挖礦產生新的區(qū)塊
     * @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");
    }

    /**
     * 新建一個區(qū)塊
     * @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);
        }

    }
}

運行結果:

測試運行結果
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末婴梧,一起剝皮案震驚了整個濱河市下梢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌志秃,老刑警劉巖怔球,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浮还,居然都是意外死亡竟坛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門钧舌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來担汤,“玉大人,你說我怎么就攤上這事洼冻≌钙纾” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵撞牢,是天一觀的道長率碾。 經常有香客問我,道長屋彪,這世上最難降的妖魔是什么所宰? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮畜挥,結果婚禮上仔粥,老公的妹妹穿的比我還像新娘。我一直安慰自己蟹但,他們只是感情好躯泰,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著华糖,像睡著了一般麦向。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上客叉,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天诵竭,我揣著相機與錄音景描,去河邊找鬼蚕愤。 笑死万细,一個胖子當著我的面吹牛厢绝,可吹牛的內容都是我干的脱吱。 我是一名探鬼主播状土,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼拗军,長吁一口氣:“原來是場噩夢啊……” “哼苟翻!你這毒婦竟也來了叽躯?” 一聲冷哼從身側響起再扭,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤氧苍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后泛范,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體让虐,經...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年罢荡,在試婚紗的時候發(fā)現(xiàn)自己被綠了赡突。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡区赵,死狀恐怖惭缰,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情笼才,我是刑警寧澤漱受,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站骡送,受9級特大地震影響昂羡,放射性物質發(fā)生泄漏。R本人自食惡果不足惜摔踱,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一虐先、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昌渤,春花似錦赴穗、人聲如沸憔四。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽了赵。三九已至潜支,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柿汛,已是汗流浹背冗酿。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工埠对, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人裁替。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓项玛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弱判。 傳聞我的和親對象是個殘疾皇子襟沮,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內容