本文构建的区块链达不到生产级别,只是为了更好的理解区块链的概念。
理论
1.基本数据结构
由下图可知,区块链本质是一个链表,没有用指针,而是通过特定构造的哈希值来连接前后节点。
2.新增节点
区块链是不断增长的,新增节点需要满足一定条件:
1 第 N+1 个区块基于第 N 个区块的信息生成,保证链上信息的含义是连续的;
2 生成第 N+1 个区块需要限制时间间隔,避免无序增长。
条件 1 可以由下面函数确定, 表示某种哈希函数, 表示节点哈希值, 表示某节点所包含的信息。
条件 2 则通过加入某种“难题”来确定,比如每次挖矿需要找到额外参数 , 使得需要计算出的哈希值必须满足前 x 位为 0,才会被认可。
极简的一个区块链与挖矿实现
定义区块类
import java.util.Date;
public class Block {
public String hash; //区块的哈希值
public String previousHash; //前一个区块的哈希值
private String data; //一些简单的信息,用来参与哈希运算
private long timeStamp; //时间戳
private int nonce; //记录挖矿所用的哈希运算次数,也是用来衡量挖矿难度的指标
//构造函数
public Block(String data, String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
this.hash = calculateHash();
}
//区块哈希值计算函数
public String calculateHash() {
String calculatedhash = StringUtil.applySha256(
previousHash +
Long.toString(timeStamp) +
Integer.toString(nonce) +
data
);
return calculatedhash;
}
//挖矿函数
public void mineBlock(int difficulty) {
//需要根据hash值前几位的0的数量来做工作量证明
String target = new String(new char[difficulty]).replace('\0', '0');
while(!hash.substring( 0, difficulty).equals(target)) {
nonce ++;
hash = calculateHash();
}
System.out.println("Block Mined!!! : " + hash);
}
}
封装SHA256算法
import java.security.MessageDigest;
public class StringUtil {
//只需要知道这个函数能应用sha256算法,返回一个hash值
public static String applySha256(String input){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes("UTF-8"));
StringBuffer hexString = new StringBuffer();
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);
}
}
}
主程序
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) {
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');
for(int i=1; i < blockchain.size(); i++) {
currentBlock = blockchain.get(i);
previousBlock = blockchain.get(i-1);
//检查当前区块hash值
if(!currentBlock.hash.equals(currentBlock.calculateHash()) ){
System.out.println("Current Hashes not equal");
return false;
}
//检查当前区块的previousHash值
if(!previousBlock.hash.equals(currentBlock.previousHash) ) {
System.out.println("Previous Hashes not equal");
return false;
}
//检查当前区块是否被挖出,是否满足工作量证明
if(!currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {
System.out.println("This block hasn't been mined");
return false;
}
}
return true;
}
}
输出结果
Blockchain is Valid: true
The block chain:
[
{
"hash": "00000d90c888bedcf24e46e3753afb5fdcb956d34c3d4edf8bec969f3fcc4548",
"previousHash": "0",
"data": "Hi im the first block",
"timeStamp": 1581343301486,
"nonce": 1598747
},
{
"hash": "000006607ab6534596f388cc88709c7dabab8dfd4ce1436cb8e91192e5bdd2bf",
"previousHash": "00000d90c888bedcf24e46e3753afb5fdcb956d34c3d4edf8bec969f3fcc4548",
"data": "Yo im the second block",
"timeStamp": 1581343305531,
"nonce": 416510
},
{
"hash": "000006319344772c1f2f8b42691dce889a08d44194017443493118004252965e",
"previousHash": "000006607ab6534596f388cc88709c7dabab8dfd4ce1436cb8e91192e5bdd2bf",
"data": "Hey im the third block",
"timeStamp": 1581343306307,
"nonce": 2320874
}
]