(译文部分是自己练习英语翻译的……顺便了解一下区块链)
这里写的一系列的教程目的是帮助你构建一个蓝图,教你怎么样开发区块链技术。
本节主要内容:
写你的第一个(非常)基础的区块链demo
实现一个简单的挖矿系统
惊叹所能做到的可能性(PS:老外写文章啊啊啊啊啊啊啊啊)
(我假设你有面向对象编程的基础)
值得注意的是这个demo是一个完整运转,为生产区块链做准备。但是它只是一个概念证明的实现来帮助你理解未来教程:什么是区块链。
你可以在未来的教程中支持:
btc(比特币):17svYzRv4XJ1Sfi1TSThp3NBFnh7Xsi6fu
环境配置
我使用Java,你应该遵循面向对象语言的设计。我使用的IDE是Eclipse,但是你可以使用任何新的花哨的编辑器(尽管你会错过好多的膨胀 PS:WTF?)
Jdk的安装
Eclispe(或者其他的IDE/Text Editor)
你可以通过谷歌获取一个gson库(可选),这样我们可以把对象转换成json格式的数据。这个库是非常有用的,我们还将进一步使用peer2peer的东西,但可以使用另一种方法获取。
在Eclispe中创建一个Java工程(file > new > )。我给它取名为"noobchain",并创建了一个相同名字的类"NoobChain"。
现在可以开始了。
制作一个区块链项目
"blockchain"就是一个区块的链条/列表。每个区块拥有他们自己的数字签名,这个签名还包含之前区块的数字签名和一些数据(这个数据可以是交易的例子)
Hash = 数字签名
每个区块不仅包含了之前区块的hash值,它还包括在块中自己的hash值,它的hash值由签名的hash经过算法来得到的。如果之前的区块数据被修改了,那么前面的区块的hash值也要变(因为hash值的一部分是通过数据计算的)进而影响整个区块的hash值。我们可以通过计算和比较hash值知道这个区块链是否作废了。
这什么意思?…改动这个列表中任何的数据都会修改数字签名导致这个链无效。
接下来让我首次尝试创建一个类来制作区块链:
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变量是记录前一个的区块的hash值和字符串数据来保存我们的块数据。
接下来,我们需要一个生成数字签名的方法,有很多加密算法由你选择,然而只有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);
}
}
}
如果你不理解这个helper方法也不要担心,你只需要知道通过它传入字符串应用于SHA256算法上,返回生成的字符串类型的数字签名就行。
现在我们在Block类中添加一个新方法使用SHA256去计算hash值。我们必须计算我们不想修改的区块的所有部分的hash值。所以我们的区块类中包含previousHash、data、timeStamp属性。
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中,我们创建一些区块并打印它们的hash值到屏幕上,以查看一切都在正常工作。
第一个区块被叫做genesis区块,因为它没有上一个区块我们将把0作为它的previousHash值。
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);
}
}
输入应该是这样的:
现在每个区块都有基于它们的信息和前一个数字签名而生成的自己的数字签名了,
目前,它还不是一个区块链,让我们存储我们的区块到一个ArrayList中,并且我们倒入gson去以json的格式查看它们。
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);
}
}
现在我们的输出应该看起来更接近我们所期望的一个区块链的样子。
现在我们需要一个检查我们区块链的完整性的方法。
让我们创建Boolean类型的isChainValid()方法在NoobChain类中。它将会循环所有的在链中的区块并比较它们的hash值。这个方法需要检查hash变量是否真正与计算的hash相等,还要检查上一个区块的hash值是否与previousHash属性相等。
加下来任何区块链的修改都会造成这个方法返回false。
在比特币节点网络中共享他们的块链,最长的有效的链被网络所接受。是什么组织某人钻该旧区块的数据然后创建一个全新的更长的区块链并呈现给网络的?是工作证明。工作系统的hashcash证明意思是需要相当长的时间和计算能力去创建新的块。因此攻击者需要比其他同行相结合更多的计算能力。
让我们开始矿工区块把。
我们要求矿工通过在区块中尝试不同变量值验证工作,直到它的hash以一定数量的0开始。
让我们添加int类型的nonce属性并且在calculateHash()方法中包含它,然后添加需要的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);
}
}
mineBlock()方法有个名为difficulty的int类型的参数,这是他们必须解决的0的个数。大多数计算机上几乎可以立即解决像1或2(hash值开头的0的个数)这样的低难度,我建议以4-6测试。写本篇文章时,Litecoin的难度在442592左右。
让我们添加静态变量difficulty到NoobChain类中:
public static int difficulty = 5;
我们应该更新NoobChain类在每次新生成区块的时候触发mineBlock()方法。isChainValid()方法也应该检查是否每个块都有由矿工挖出的hash值。
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;
}
}
运行结果如下:
挖掘每一个区块都需要一些时间(大约3秒)你应该弄清难度值,看看它是怎么样影响一个块的开采时间的。
如果有人篡改了数据在你的区块链系统中:
他们的区块链将是不合法的
他们没有能力创建一个更长的区块链
在你的网络中诚实的区块链将有最长的链条上的时间优势
窜在区块链将没有能力赶上更长的有效链。
除非他们计算速度比你的网络中所有其他节点的总和大得多。未来的量子计算机或某个东西吧。
现在你完成了你最基础的区块链了!
你的区块链有一下特征:
由存储的数据创造的区块。
有数字签名链接着你所有的区块链。
要求矿工工作证明检验新的区块。
可以检查它的数据是否有效和不可改变。
你可以下载这个project文件on Github:
https://github.com/CryptoKass/NoobChain-Tutorial-Part-1
你可以在这里下载作者的源码