本篇文章將和大家一起分享區(qū)塊鏈技術(shù)的概念,還會使用 Java 來實現(xiàn)一個基本的應用程序。此外還會討論關(guān)于該技術(shù)的一些先進概念以及實際應用。以下是詳情內(nèi)容。
什么是區(qū)塊鏈?
那么,讓我們先來了解一下區(qū)塊鏈到底是什么…
好吧,它的起源可以追溯到Satoshi Nakamoto在2008年發(fā)表的關(guān)于比特幣的白皮書。
區(qū)塊鏈是一個分散的信息分類帳。它由通過使用密碼學連接的數(shù)據(jù)塊組成。它屬于通過公共網(wǎng)絡連接的節(jié)點網(wǎng)絡。當我們稍后嘗試構(gòu)建一個基本教程時,我們將更好地理解這一點。
我們必須了解一些重要的屬性,讓我們來了解一下:
- 防篡改 :首先,數(shù)據(jù)作為塊的一部分是防篡改的。每個塊都由一個加密摘要(通常稱為散列)引用,使得塊能夠防篡改。
- 去中心化 :整個區(qū)塊鏈在網(wǎng)絡上完全去中心化。這意味著沒有主節(jié)點,網(wǎng)絡中的每個節(jié)點都有相同的副本。
- 透明 :每個參與網(wǎng)絡的節(jié)點通過與其他節(jié)點協(xié)商一致,對其鏈進行驗證并添加新的塊。因此,每個節(jié)點都具有數(shù)據(jù)的完全可見性。
區(qū)塊鏈是如何工作的?
現(xiàn)在,讓我們來了解區(qū)塊鏈是如何工作的。
區(qū)塊鏈的基本單位是區(qū)塊。單個塊可以封裝多個事務或其他有價值的數(shù)據(jù):
開采區(qū)塊
我們用散列值表示一個塊。生成塊的哈希值稱為“挖掘”塊。開采一個區(qū)塊通常計算成本很高,因為它是“工作證明”。
塊的散列通常由以下數(shù)據(jù)組成:
- 首先,塊的散列由它封裝的事務組成
- 散列還包括塊創(chuàng)建的時間戳
- 它還包括一個nonce,一個用于密碼學的任意數(shù)字
- 最后,當前塊的散列還包括前一塊的散列
- 網(wǎng)絡中的多個節(jié)點可以同時競爭挖掘塊。除了生成散列,節(jié)點還必須驗證添加到塊中的事務是否合法。第一個挖方塊的人贏得比賽!
向區(qū)塊鏈中添加區(qū)塊
雖然挖掘塊的計算成本很高,但驗證塊是否合法相對容易得多。網(wǎng)絡中的所有節(jié)點都參與驗證新開采的區(qū)塊。
因此, 在節(jié)點一致的情況下,一個新挖掘的區(qū)塊被添加到區(qū)塊鏈中。
現(xiàn)在,有幾種共識協(xié)議可供我們用于驗證。網(wǎng)絡中的節(jié)點使用相同的協(xié)議來檢測鏈的惡意分支。因此,即使引入惡意分支,也會很快被大多數(shù)節(jié)點拒絕。
Java中的基本區(qū)塊鏈
現(xiàn)在我們已經(jīng)有足夠的上下文開始用Java構(gòu)建一個基本的應用程序。
我們這里的簡單示例將說明我們剛才看到的基本概念。生產(chǎn)級應用程序需要考慮很多問題,這些問題超出了本教程的范圍。不過,我們稍后將討論一些高級主題。
實現(xiàn)塊
首先,我們需要定義一個簡單的POJO來保存塊的數(shù)據(jù):
public class Block {
private String hash;
private String previousHash;
private String data;
private long timeStamp;
private int nonce;
public Block(String data, String previousHash, long timeStamp) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = timeStamp;
this.hash = calculateBlockHash();
}
// standard getters and setters
}
讓我們了解一下我們在這里打包的東西:
nonce
計算散列
現(xiàn)在,我們?nèi)绾斡嬎銐K的散列呢?我們已經(jīng)使用了 calculateBlockHash 方法,但還沒有看到實現(xiàn)。在我們實現(xiàn)這個方法之前,花點時間來理解什么是散列是值得的。
散列是散列函數(shù)的輸出。 哈希函數(shù)將任意大小的輸入數(shù)據(jù)映射為固定大小的輸出數(shù)據(jù)。 哈希對輸入數(shù)據(jù)中的任何更改都非常敏感,無論更改多么小。
此外,僅僅從散列中獲取輸入數(shù)據(jù)是不可能的。這些屬性使得哈希函數(shù)在密碼學中非常有用。
那么,讓我們看看如何在Java中生成塊的哈希:
public String calculateBlockHash() {
String dataToHash = previousHash
+ Long.toString(timeStamp)
+ Integer.toString(nonce)
+ data;
MessageDigest digest = null;
byte[] bytes = null;
try {
digest = MessageDigest.getInstance("SHA-256");
bytes = digest.digest(dataToHash.getBytes(UTF_8));
} catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
logger.log(Level.SEVERE, ex.getMessage());
}
StringBuffer buffer = new StringBuffer();
for (byte b : bytes) {
buffer.append(String.format("%02x", b));
}
return buffer.toString();
}
public String calculateBlockHash() {
String dataToHash = previousHash
+ Long.toString(timeStamp)
+ Integer.toString(nonce)
+ data;
MessageDigest digest = null;
byte[] bytes = null;
try {
digest = MessageDigest.getInstance("SHA-256");
bytes = digest.digest(dataToHash.getBytes(UTF_8));
} catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
logger.log(Level.SEVERE, ex.getMessage());
}
StringBuffer buffer = new StringBuffer();
for (byte b : bytes) {
buffer.append(String.format("%02x", b));
}
return buffer.toString();
}
這里發(fā)生了很多事情,讓我們詳細了解一下:
MessageDigest
我們在那塊地上挖礦了嗎?
到目前為止,一切聽起來都簡單而優(yōu)雅,只是我們還沒有開采這個區(qū)塊。那么,究竟需要挖掘一個區(qū)塊,這已經(jīng)吸引了開發(fā)人員一段時間的想象力!
嗯,挖掘一個區(qū)塊意味著為這個區(qū)塊解決一個計算復雜的任務。雖然計算一個塊的散列有點瑣碎,但找到以五個零開始的散列卻不是。更復雜的是找到一個以十個零開始的散列,我們就得到了一個大概的想法。
那么,我們到底該怎么做呢?老實說,這個解決方案沒有那么花哨!我們是用蠻力來達到這個目標的。我們在這里使用 nonce :
public String mineBlock(int prefix) {
String prefixString = new String(new char[prefix]).replace('