写这篇随笔主要是尝试帮助自己了解如何学习区块链技术开发。
【本文禁止任何形式的全文粘贴式转载,本文来自zacky31的随笔】
目标:
- 创建一个最基本的“区块链”
- 实现一个简单的挖矿系统
前提:
对面向对象编程有一定的基础
注意:
值得注意的是,这不会是一个完整的功能,恰恰相反,这是一个概念证明的实例,可以帮助您进一步了解区块链。
准备:
我将会使用Java来实现,当然你也可以使用任何面向对象的语言。
环境:
- JDK 8
- IDEA
- Maven
开始吧
区块链就好比多个块连接起来。其中每一块都将拥有自己的签名,签名中包含其前面的块信息和一些数据(例如交易信息)。
每个块不仅仅包含它之前的块信息,同时也包含自身。如果前面一块内容改变了,其 hash 值也会改变,将会导致其后面所有的块发生变化。通过计算和比较所得的 hash 值,我们可以判断区块链是否合法。换句话说,改变区块链中的任意内容,将会改变整个区块链的签名。
根据上面的分析,我们先创建一个 Block 类。
importjava.util.Date; public classBlock { public String hash; //存放数字签名 public String preHash; //前面块的签名 privateString data; private longtimeStamp; publicBlock(String data, String preHash) { this.data =data; this.preHash =preHash; this.timeStamp = newDate().getTime(); } }
接下来,我们需要一个生成签名的方法。有很多加密算法可供选择,这里使用 SHA256 刚刚好。
importjava.security.MessageDigest; public classStringUtil { public staticString applySha256(String input) { try{ MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(input.getBytes("UTF-8")); StringBuilder hexString = newStringBuilder(); 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); } returnhexString.toString(); } catch(Exception e) { throw newRuntimeException(e); } } }
现在,我们向 Block 类中添加计算数字签名的方法,并修改一下其构造方法。
publicBlock(String data, String preHash) { this.data =data; this.preHash =preHash; this.timeStamp = newDate().getTime(); this.hash =calculateHash(); } publicString calculateHash() { String calculatedhash = StringUtil.applySha256(preHash + Long.toString(timeStamp) +data); returncalculatedhash; }
到这里,可以写个 Main 方法看一下效果。
public classMain { public static voidmain(String[] args) { Block first = new Block("Hi i am the first block", "0"); System.out.println("Hash for block 1 : " +first.hash); Block second = new Block("Hi i am the second block", first.hash); System.out.println("Hash for block 2 : " +second.hash); Block third = new Block("Hi i am the third block", second.hash); System.out.println("Hash for block 3 : " +third.hash); } }
可以看见每个 Block 都有自己唯一的 数字签名,当然,现在还没有构成一个区块链,将这些块存放到一个 ArrayList 中吧。修改 Main 类后再次运行。
importcom.google.gson.GsonBuilder; importjava.util.ArrayList; public classMain { public static ArrayList<Block> blockchain = new ArrayList<Block>(); public static voidmain(String[] args) { blockchain.add(new Block("Hi i am the first block", "0")); blockchain.add(new Block("Hi i am the second block", blockchain.get(blockchain.size() - 1).hash)); blockchain.add(new Block("Hi i am the third block", blockchain.get(blockchain.size() - 1).hash)); String blockchainJson = newGsonBuilder().setPrettyPrinting().create().toJson(blockchain); System.out.println(blockchainJson); } }
现在,需要一种方法去验证创建的区块链。编写一段 isChainValid() 方法。任何块的改变将会导致这个方法失效。
public staticBoolean isChainValid() { Block currentBlock; Block previousBlock; for (int i = 1; i < blockchain.size(); i++) { currentBlock =blockchain.get(i); previousBlock = blockchain.get(i - 1); if (!currentBlock.hash.equals(currentBlock.calculateHash())) { System.out.println("Current Hashes not equal!"); return false; } if (!previousBlock.hash.equals(currentBlock.preHash)) { System.out.println("Previous Hashes not equal!"); return false } } return true; }
接下来,尝试一下挖矿!
在 Block 类中,新增一个变量 nonce,并且添加到 calculateHash() 这个方法中,同时需要 mineBlock() 这个方法。这个方法中的 difficulty 变量就是用来控制计算量的。当设置的值较低时,大部分计算机很快就能算出来。
importjava.util.Date;
public classBlock {
publicString hash;
publicString preHash;
privateString data;
private longtimeStamp;
private intnonce;
publicBlock(String data, String preHash) {
this.data =data;
this.preHash =preHash;
this.timeStamp = newDate().getTime();
this.hash =calculateHash();
}
publicString calculateHash() {
String calculatedhash = StringUtil.applySha256(preHash + Long.toString(timeStamp) + Integer.toString(nonce) +
data);
returncalculatedhash;
}
public void mineBlock(intdifficulty) {
String target = new String(new char[difficulty]).replace('