使用Java創建第一個區塊鏈

本系列教程的目的是幫助你瞭解如何開發區塊鏈技術。在本教程中,我們將:

  • 創建你的第一個非常基礎的區塊鏈。
  • 實施簡單的工作量證明系統(採礦)。
  • 探討任何的可能性。

我假設你對面向對象編程有基本的瞭解。值得注意的是,這不是一個功能齊全的生產區塊鏈。相反,這是一個概念驗證實現,可幫助你瞭解區塊鏈對於未來教程中區塊鏈的作用。

配置

我們將使用Java,但你應該能夠使用任何OOP語言。我將使用Eclipse,但你可以使用任何新的花哨的文本編輯器(雖然你會錯過很多好的擴展)。

你會需要:

  • 安裝了Java和JDK。
  • Eclipse或其他IDE。

或者你可以通過谷歌獲取GSON庫。這將允許我們將對象轉換爲Json。這是一個非常有用的庫,我們也將在peer2peer中使用更多的東西,但是可以隨意使用替代方法。

在Eclipse中(file> new>)創建一個Java項目。我將把我的項目稱爲noobchain,並使用相同的名稱創建一個新類NoobChain

使用Java創建第一個區塊鏈

現在你就可以去試試:)

創建區塊鏈。

區塊鏈只是一個鏈/列表塊。區塊鏈中的每個區塊都有自己的數字簽名,包含前一個區塊的數字簽名,並且有一些數據(例如,這些數據可能是交易)。

使用Java創建第一個區塊鏈

哈希=數字簽名。

每個塊不僅包含之前塊的哈希值,而且它自己的哈希部分是從前一個哈希計算的。如果前一個塊的數據被改變,那麼前一個塊的哈希將改變(因爲它部分地由數據計算),進而影響其後的塊的所有哈希。計算和比較哈希值可以讓我們看到區塊鏈是否無效。

這是什麼意思?...更改此列表中的任何數據,將更改簽名並破壞區塊鏈。

所以先讓我們創建構成區塊鏈的類Block:

import java.util.Date;

public class Block {

    public String hash;
    public String previousHash;
    private String data; //our data will be a simple message.
    private long timeStamp; //as number of milliseconds since 1/1/1970.

    //Block Constructor.
    public Block(String data,String previousHash ) {
        this.data = data;
        this.previousHash = previousHash;
        this.timeStamp = new Date().getTime();
    }
}

正如你所看到的,我們的基本塊包含一個String hash,它將保存我們的數字簽名。變量previousHash用於保存前一個塊的哈希和String data以保存我們的塊數據。

接下來我們需要一種生成數字簽名的方法,你可以選擇許多加密算法,但SHA256適用於此示例。我們可以import java.security.MessageDigest;訪問SHA256算法。

我們需要稍後使用SHA256,以便在新的StringUtil utility類中創建一個方便的helper方法:

import java.security.MessageDigest;

public class StringUtil {
    //Applies Sha256 to a string and returns the result. 
    public static String applySha256(String input){     
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");            
            //Applies sha256 to our input, 
            byte[] hash = digest.digest(input.getBytes("UTF-8"));           
            StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
            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);
        }
    }   
}

如果你不理解這個幫助方法的內容,不要太擔心,你需要知道的是它需要一個字符串並對其應用SHA256算法,並將生成的簽名作爲字符串返回。

現在讓我們使用我們的applySha256 helper,在Block類的新方法中計算哈希值。我們必須計算我們不想被篡改的塊的所有部分的哈希值。因此,對於我們的塊,我們將包括previousHashdatatimeStamp


public String calculateHash() {
    String calculatedhash = StringUtil.applySha256( 
            previousHash +
            Long.toString(timeStamp) +
            data 
            );
    return calculatedhash;
}

並讓我們將此方法添加到Block構造函數中 ...

    public Block(String data,String previousHash ) {
        this.data = data;
        this.previousHash = previousHash;
        this.timeStamp = new Date().getTime();
        this.hash = calculateHash(); //Making sure we do this after we set the other values.
    }

一些測試時間......

在我們的主NoobChain類中,我們可以創建一些塊並將哈希值打印到屏幕上,以查看所有內容是否正常工作。

讓我們測試一下......第一個塊稱爲genesis塊,因爲沒有先前的塊,我們只需輸入“0”作爲前一個哈希。

public class NoobChain {

    public static void main(String[] args) {

        Block genesisBlock = new Block("Hi im the first block", "0");
        System.out.println("Hash for block 1 : " + genesisBlock.hash);

        Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
        System.out.println("Hash for block 2 : " + secondBlock.hash);

        Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
        System.out.println("Hash for block 3 : " + thirdBlock.hash);

    }
}

輸出應該類似於:

使用Java創建第一個區塊鏈

你的值會有所不同,因爲你的時間戳會有所不同。

每個塊現在都有自己的數字簽名,基於其信息和前一個塊的簽名。

目前它不是一個區塊鏈,所以讓我們將塊存儲在ArrayList中,並導入gson以將其視爲Json。(單擊此處瞭解如何導入gson庫)

import java.util.ArrayList;
import com.google.gson.GsonBuilder;

public class NoobChain {

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

    public static void main(String[] args) {    
        //add our blocks to the blockchain ArrayList:
        blockchain.add(new Block("Hi im the first block", "0"));        
        blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash)); 
        blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));

        String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);      
        System.out.println(blockchainJson);
    }

}

現在我們的輸出應該看起來更接近我們對區塊鏈的期望。

現在我們需要一種方法來檢查區塊鏈的完整性。

讓我們在NoobChain類中創建一個isChainValid()的布爾值方法,它將遍歷鏈中的所有塊並比較哈希值。此方法需要檢查哈希變量實際上是否等於計算的哈希值,並且前一個塊的哈希值等於previousHash變量。

public static Boolean isChainValid() {
    Block currentBlock; 
    Block previousBlock;

    //loop through blockchain to check hashes:
    for(int i=1; i < blockchain.size(); i++) {
        currentBlock = blockchain.get(i);
        previousBlock = blockchain.get(i-1);
        //compare registered hash and calculated hash:
        if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
            System.out.println("Current Hashes not equal");         
            return false;
        }
        //compare previous hash and registered previous hash
        if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
            System.out.println("Previous Hashes not equal");
            return false;
        }
    }
    return true;
}

對區塊鏈塊的任何更改都將導致此方法返回false

在比特幣網絡節點上共享其區塊鏈,並且網絡接受最長的有效鏈。什麼阻止某人篡改舊塊中的數據然後創建一個全新的更長的區塊鏈並將其呈現給網絡?工作量證明。工作系統的hashcash證明意味着創建新塊需要相當多的時間和計算能力。因此,***者需要比其他對等組合更多的計算能力。

讓我們開始挖掘塊!

我們將要求礦工通過在塊中嘗試不同的變量值來進行工作量證明,直到其哈希以一定數量的0開始。

讓我們在calculateHash()方法中添加一個名爲nonceint,以及非常需要的mineBlock()方法:

import java.util.Date;

public class Block {

    public String hash;
    public String previousHash; 
    private String data; //our data will be a simple message.
    private long timeStamp; //as number of milliseconds since 1/1/1970.
    private int nonce;

    //Block Constructor.  
    public Block(String data,String previousHash ) {
        this.data = data;
        this.previousHash = previousHash;
        this.timeStamp = new Date().getTime();

        this.hash = calculateHash(); //Making sure we do this after we set the other values.
    }

    //Calculate new hash based on blocks contents
    public String calculateHash() {
        String calculatedhash = StringUtil.applySha256( 
                previousHash +
                Long.toString(timeStamp) +
                Integer.toString(nonce) + 
                data 
                );
        return calculatedhash;
    }

    public void mineBlock(int difficulty) {
        String target = new String(new char[difficulty]).replace('\0', '0'); //Create a string with difficulty * "0" 
        while(!hash.substring( 0, difficulty).equals(target)) {
            nonce ++;
            hash = calculateHash();
        }
        System.out.println("Block Mined!!! : " + hash);
    }
}

實際上,每個礦工將從隨機點開始迭代。一些礦工甚至可以嘗試隨機數來獲取隨機數。另外值得注意的是,在更難的解決方案可能需要超過integer.MAX_VALUE,礦工可以嘗試更改時間戳。

mineBlock()方法接受一個名爲difficultyint,這中間必須解決的數量爲0的問題。在大多數計算機上幾乎可以立即解決像1或2這樣的低難度問題,我建議在4-6左右進行難度測試。在撰寫本文時,Litecoin的難度大約是442,592。

讓我們將難度作爲靜態變量添加到NoobChain類:

public static int difficulty = 5; 

我們應該更新NoobChain類以觸​​發每個新塊的mineBlock()方法。isChainValid()布爾值還應檢查每個塊是否具有已解決(通過挖掘)哈希。

import java.util.ArrayList;
import com.google.gson.GsonBuilder;

public class NoobChain {

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

    public static void main(String[] args) {    
        //add our blocks to the blockchain ArrayList:

        blockchain.add(new Block("Hi im the first block", "0"));
        System.out.println("Trying to Mine block 1... ");
        blockchain.get(0).mineBlock(difficulty);

        blockchain.add(new Block("Yo im the second block",blockchain.get(blockchain.size()-1).hash));
        System.out.println("Trying to Mine block 2... ");
        blockchain.get(1).mineBlock(difficulty);

        blockchain.add(new Block("Hey im the third block",blockchain.get(blockchain.size()-1).hash));
        System.out.println("Trying to Mine block 3... ");
        blockchain.get(2).mineBlock(difficulty);    

        System.out.println("\nBlockchain is Valid: " + isChainValid());

        String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
        System.out.println("\nThe block chain: ");
        System.out.println(blockchainJson);
    }

    public static Boolean isChainValid() {
        Block currentBlock; 
        Block previousBlock;
        String hashTarget = new String(new char[difficulty]).replace('\0', '0');

        //loop through blockchain to check hashes:
        for(int i=1; i < blockchain.size(); i++) {
            currentBlock = blockchain.get(i);
            previousBlock = blockchain.get(i-1);
            //compare registered hash and calculated hash:
            if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
                System.out.println("Current Hashes not equal");         
                return false;
            }
            //compare previous hash and registered previous hash
            if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
                System.out.println("Previous Hashes not equal");
                return false;
            }
            //check if hash is solved
            if(!currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {
                System.out.println("This block hasn't been mined");
                return false;
            }
        }
        return true;
    }
}

請注意,我們還檢查並打印isChainValid

運行此結果應如下所示:

使用Java創建第一個區塊鏈

挖掘每個區塊需要一些時間!(大約3秒)你應該弄亂難度值,看看這會影響挖掘每個區塊的時間。

如果有人要篡改區塊鏈系統中的數據:

  • 他們的區塊鏈無效。
  • 他們無法創建更長的區塊鏈。
  • 你網絡中的誠實區塊鏈將在最長的鏈條上具有時間優勢。

被篡改的區塊鏈將無法趕上更長且有效的鏈條。

除非它們的計算速度遠遠超過網絡中所有其他節點的總和。未來的量子計算機或其他東西。

你已經完成了基本的區塊鏈!

你的區塊鏈:

  • 由存儲數據的塊組成。
  • 具有將你的塊鏈接在一起的數字簽名。
  • 需要工作挖掘證明來驗證新塊。
  • 可以檢查其中的數據是否有效且未更改。

你可以在Github上下載項目文件。

======================================================================

分享一些以太坊、EOS、比特幣等區塊鏈相關的交互式在線編程實戰教程:

  • java以太坊開發教程,主要是針對java和android程序員進行區塊鏈以太坊開發的web3j詳解。
  • python以太坊,主要是針對python工程師使用web3.py進行區塊鏈以太坊開發的詳解。
  • php以太坊,主要是介紹使用php進行智能合約開發交互,進行賬號創建、交易、轉賬、代幣開發以及過濾器和交易等內容。
  • 以太坊入門教程,主要介紹智能合約與dapp應用開發,適合入門。
  • 以太坊開發進階教程,主要是介紹使用node.js、mongodb、區塊鏈、ipfs實現去中心化電商DApp實戰,適合進階。
  • C#以太坊,主要講解如何使用C#開發基於.Net的以太坊應用,包括賬戶管理、狀態與交易、智能合約開發與交互、過濾器和交易等。
  • EOS教程,本課程幫助你快速入門EOS區塊鏈去中心化應用的開發,內容涵蓋EOS工具鏈、賬戶與錢包、發行代幣、智能合約開發與部署、使用代碼與智能合約交互等核心知識點,最後綜合運用各知識點完成一個便籤DApp的開發。
  • java比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈存儲、去中心化共識機制、密鑰與腳本、交易與UTXO等,同時也詳細講解如何在Java代碼中集成比特幣支持功能,例如創建地址、管理錢包、構造裸交易等,是Java工程師不可多得的比特幣開發學習課程。
  • php比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈存儲、去中心化共識機制、密鑰與腳本、交易與UTXO等,同時也詳細講解如何在Php代碼中集成比特幣支持功能,例如創建地址、管理錢包、構造裸交易等,是Php工程師不可多得的比特幣開發學習課程。
  • tendermint區塊鏈開發詳解,本課程適合希望使用tendermint進行區塊鏈開發的工程師,課程內容即包括tendermint應用開發模型中的核心概念,例如ABCI接口、默克爾樹、多版本狀態庫等,也包括代幣發行等豐富的實操代碼,是go語言工程師快速入門區塊鏈開發的最佳選擇。

匯智網原創翻譯,轉載請標明出處。這裏是原文使用Java創建第一個區塊鏈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章