代碼格式可能有錯誤,可以點擊閱讀原文查看代碼
讓我們來看看用 Java 代碼實現區塊鏈的可能性。我們從基本原理出發,開發一些代碼來演示它們是如何融合在一起的。
Bitcoin炙手可熱 —— 多么的輕描淡寫。雖然數字加密貨幣的前景尚不明確,但區塊鏈 —— 用于驅動比特幣的技術 —— 卻非常流行。
區塊鏈的應用領域尚未探索完畢。它也有可能會破壞企業自動化。關于區塊鏈的工作原理,有很多可用的信息。我們有一個深度區塊鏈的免費白皮書(無需注冊)。
本文將重點介紹區塊鏈體系結構,特別是通過簡單的代碼示例演示“不可變,僅附加”的分布式賬本是如何工作的。
作為開發者,閱讀代碼會比閱讀技術文章更容易理解。至少對我來說是這樣。那么我們開始吧!
簡述區塊鏈
首先我們簡要總結下區塊鏈。區塊包含一些頭信息和任意一組數據類型或一組交易。該鏈從第一個(初始)區塊開始。隨著交易被添加/擴展,將基于區塊中可以存儲多少交易來創建新區塊。
當超過區塊閥值大小時,將創建一個新的交易區塊。新區塊與前一個區塊連接,因此稱為區塊鏈。
不可變性
因為交易時會計算 SHA-256 哈希值,所以區塊鏈是不可變的。區塊鏈的內容也被哈希則提供了唯一的標識符。此外,相連的前一個區塊的哈希也會被在區塊的頭信息中散列并儲存。
這就是為什么試圖篡改區塊基本上是不可能的,至少以目前的計算能力是這樣的。下面是一個展示區塊屬性的 Java 類的部分定義。
。.. public class Block
注意,注入的泛型類型為 Tx 類型。這允許交易數據發生變化。此外,previousHash 屬性將引用前一個區塊的哈希值。稍后將描述 merkleRoot 和 nonce 屬性。
區塊哈希值
每個區塊可以計算一個哈希。這實際上是鏈接在一起的所有區塊屬性的哈希,包括前一個區塊的哈希和由此計算而得的 SHA-256 哈希。
下面是在 Block.java 類中定義的計算哈希值的方法。
。.. public void computeHash() { Gson parser = new Gson(); // 可能應該緩存這個實例 String serializedData = parser.toJson(transactions); setHash(SHA256.generateHash(timeStamp + index + merkleRoot + serializedData + nonce + previousHash)); } 。..
交易被序列化為 JSON 字符串,因此可以在哈希之前將其追加到塊屬性中。
鏈
區塊鏈通過接受交易來管理區塊。當到達預定閥值時,就創建一個區塊。下面是 SimpleBlockChain.java 的部分實現:
。.. public class SimpleBlockchain《T extends Tx》 { public static final int BLOCK_SIZE = 10; public List《Block《T》》 chain = new ArrayList《Block《T》》(); public SimpleBlockchain() { // 創建初始區塊 chain.add(newBlock()); } 。..
注意,chain 屬性維護了一個類型為 Tx 的區塊列表。此外,無參構造器 會在創建初始鏈表時初始化“初始”區塊。下面是 newBlock() 方法源碼。
。.. public Block《T》 newBlock() { int count = chain.size(); String previousHash = “root”; if (count 》 0) previousHash = blockChainHash(); Block《T》 block = new Block《T》(); block.setTimeStamp(System.currentTimeMillis()); block.setIndex(count); block.setPreviousHash(previousHash); return block; } 。..
這個方法將會創建一個新的區塊實例,產生合適的值,并分配前一個塊的哈希(這將是鏈頭的哈希),然后返回這個實例。
在將區塊添加到鏈中之前,可以通過將新區塊的上一個哈希與鏈的最后一個區塊(頭)進行比較來驗證區塊,以確保它們匹配。SimpleBlockchain.java 描述了這一過程。
。..。 public void addAndValidateBlock(Block《T》 block) { // 比較之前的區塊哈希,如果有效則添加 Block《T》 current = block; for (int i = chain.size() - 1; i 》= 0; i--) { Block《T》 b = chain.get(i); if (b.getHash().equals(current.getPreviousHash())) { current = b; } else { throw new RuntimeException(“Block Invalid”); } } this.chain.add(block); } 。..
整個區塊鏈通過循環整個鏈來驗證,確保區塊的哈希仍然與前一個區塊的哈希匹配。
以下是 SimpleBlockChain.java validate() 方法的實現。
。.. public boolean validate() { String previousHash = null; for (Block《T》 block : chain) { String currentHash = block.getHash(); if (!currentHash.equals(previousHash)) { return false; } previousHash = currentHash; } return true; } 。..
你可以看到,試圖以任何方式偽造交易數據或任何其他屬性都是非常困難的。而且,隨著鏈的增長,它會繼續變得非常、非常、非常困難,基本上是不可能的 —— 除非量子計算機可用!
添加交易
區塊鏈技術的另一個重要技術點是它是分布式的。區塊鏈只增的特性很好地幫助了它在區塊鏈網絡的節點之間的復制。節點通常以點對點的方式進行通信,就像比特幣那樣,但不一定非得是這種方式。其他區塊鏈實現使用分散的方法,比如使用基于 HTTP 協議的 API。這都是題外話了。
交易可以代表任何東西。交易可以包含要執行的代碼(例如,智能合約)或存儲和追加有關某種業務交易的信息。
智能合約:旨在以數字形式來促進、驗證或強制執行合約談判及履行的計算機協議。
就比特幣而言,交易包含所有者賬戶中的金額和其他賬戶的金額(例如,在賬戶之間轉移比特幣金額)。交易中還包括公鑰和賬戶 ID,因此傳輸需要保證安全。但這是比特幣特有的。
交易被添加到網絡中并被池化;它們不在區塊中或鏈本身中。
這是區塊鏈共識機制發揮作用的地方。現在有許多經過驗證的共識算法和模式,不過那已經超出了本文的范圍。
挖礦是比特幣區塊鏈使用的共識機制。這就是下文討論的共識類型。共識機制收集交易,用它們構建一個區塊,然后將該區塊添加到鏈中。區塊鏈會在新的交易區塊被添加之前驗證它。
默克爾樹
交易被哈希并添加到區塊中。默克爾樹被用來計算默克爾根哈希。默克爾樹是一種內部節點的值是兩個子節點值的哈希值的平衡二叉樹。而默克爾根,就是默克爾樹的根節點。
該樹用于區塊交易的驗證。如果在交易中更改了一些信息,默克爾根將失效。此外,在分布式中,它們還可以加速傳輸區塊,因為該結構只允許添加和驗證整個交易區塊所需的單個交易哈希分支。
以下是 Block.java 類中的方法,它從交易列表中創建了一個默克爾樹。
。.. public List《String》 merkleTree() { ArrayList《String》 tree = new ArrayList《》(); // 首先, // 將所有交易的哈希作為葉子節點添加到樹中。 for (T t : transactions) { tree.add(t.hash()); } int levelOffset = 0; // 當前處理的列表中的偏移量。 // 當前層級的第一個節點在整個列表中的偏移量。 // 每處理完一層遞增, // 當我們到達根節點時(levelSize == 1)停止。 for (int levelSize = transactions.size(); levelSize 》 1; levelSize = (levelSize + 1) / 2) { // 對于該層上的每一對節點: for (int left = 0; left 《 levelSize; left += 2) { // 在我們沒有足夠交易的情況下, // 右節點和左節點 // 可以一樣。 int right = Math.min(left + 1, levelSize - 1); String tleft = tree.get(levelOffset + left); String tright = tree.get(levelOffset + right); tree.add(SHA256.generateHash(tleft + tright)); } // 移動至下一層 levelOffset += levelSize; } return tree; } 。..
此方法用于計算區塊的默克爾樹根。伴隨項目有一個默克爾樹單元測試,它試圖將交易添加到一個區塊中,并驗證默克爾根是否已經更改。下面是單元測試的源碼。
。.. @Test public void merkleTreeTest() { // 創建鏈,添加交易 SimpleBlockchain《Transaction》 chain1 = new SimpleBlockchain《Transaction》(); chain1.add(new Transaction(“A”)).add(new Transaction(“B”)).add(new Transaction(“C”)).add(new Transaction(“D”)); // 獲取鏈中的區塊 Block《Transaction》 block = chain1.getHead(); System.out.println(“Merkle Hash tree :” + block.merkleTree()); //從區塊中獲取交易 Transaction tx = block.getTransactions().get(0); // 查看區塊交易是否有效,它們應該是有效的 block.transasctionsValid(); assertTrue(block.transasctionsValid()); // 更改交易數據 tx.setValue(“Z”); //當區塊的默克爾根與計算出來的默克爾樹不匹配時,區塊不應該是有效。 assertFalse(block.transasctionsValid()); } 。..
此單元測試模擬驗證交易,然后通過共識機制之外的方法改變區塊中的交易,例如,如果有人試圖更改交易數據。
記住,區塊鏈是只增的,當塊區鏈數據結構在節點之間共享時,區塊數據結構(包括默克爾根)被哈希并連接到其他區塊。所有節點都可以驗證新的區塊,并且現有的區塊可以很容易地被證明是有效的。因此,如果一個挖礦者想要添加一個偽造的區塊或者節點來調整原有的交易是不可能的。
挖礦和工作量證明
在比特幣世界中,將交易組合成區塊,然后提交給鏈中的成員進行驗證的過程叫做“挖礦”。
更寬泛地說,在區塊鏈中,這被稱為共識。現在有好幾種經過驗證的分布式共識算法,使用哪種機制取決于你有一個公共的還是私有的區塊鏈。我們的白皮書對此進行了更為深入的描述,但本文的重點是區塊鏈的原理,因此這個例子中我們將使用一個工作量證明(POW)的共識機制。
因此,挖掘節點將偵聽由區塊鏈執行的交易,并執行一個簡單的數學任務。這個任務是用一個不斷改變的一次性隨機數(nonce)來生成帶有一連串以 0 開頭的區塊哈希值,直到一個預設的哈希值被找到。
Java 示例項目有一個 Miner.java 類,其中的 proofOfWork(Block block) 方法實現如下所示。
private String proofOfWork(Block block) { String nonceKey = block.getNonce(); long nonce = 0; boolean nonceFound = false; String nonceHash = “”; Gson parser = new Gson(); String serializedData = parser.toJson(transactionPool); String message = block.getTimeStamp() + block.getIndex() + block.getMerkleRoot() + serializedData + block.getPreviousHash(); while (!nonceFound) { nonceHash = SHA256.generateHash(message + nonce); nonceFound = nonceHash.substring(0, nonceKey.length()).equals(nonceKey); nonce++; } return nonceHash; }
同樣,這是簡化的,但是一旦收到一定量的交易,這個挖礦算法會為區塊計算一個工作量證明的哈希。該算法簡單地循環并創建塊的SHA-256散列,直到產生前導數字哈希。
這可能需要很多時間,這就是為什么特定的GPU微處理器已經被實現來盡可能快地執行和解決這個問題的原因。
單元測試
你可以在 GitHub上看到結合了這些概念的 Java 示例的 JUnit 測試。
運行一下,看看這個簡單的區塊鏈是如何工作的。
另外,如果你是 C# 程序員的話,其實(我不會告訴任何人),我們也有用 C# 寫的示例。下面是 C# 區塊鏈實現的示例。
最后的思考
希望這篇文章能讓你對區塊鏈技術有一定的了解,并有充足的興趣繼續研究下去。
本文介紹的所有示例都用于我們的深度區塊鏈白皮書 (無需注冊即可閱讀)。 這些例子在白皮書中有更詳細的說明。
另外,如果你想在 Java 中看到完整的區塊鏈實現,這里有一個開源項目 BitcoinJ 的鏈接。你可以看到上文的概念在實際生產中一一實現。
來源:區塊網
評論