用nodejs+vue实现一个简易的区块链,包括区块链账本、点对点通信、以及pow共识机制。
用户上线后向临近节点建立连接,互相交换本地账本,如果对方账本长度大于本地账本长度,则用对方账本覆盖本地账本。
用户可以在2P网络上广播交易信息,并对交易信息进行打包,打包成功后发布至其它节点,节点收到其他节点打包的区块后会对区块进行验证,验证通过则把收到的区块加入到本地的区块链中。
本节介绍区块链表的实现。
一、定义区块block
首先我们需要定义一个区块,一个区块包含区块的索引、哈希值、时间戳、pow随机数、前一个区块的哈希值以及其打包的数据。在block.js中定义区块。
class Block {
constructor(index, preHash, timestamp, data, hash, noce) {
this.index = index
this.preHash = preHash
this.timestamp = timestamp
this.data = data
this.hash = hash
this.noce = noce
}
二、定义区块链chain
区块需要保存在区块链中,一个区块链应该包含一个区块链结构用以存储区块,并且实现一些方法,例如创建区块、验证区块有效性、添加区块到区块链中。
1.定义一个区块链类
定义一个区块链类,通过硬编码定义创世区块并添加到链中。
class Chain {
constructor() {
this.chain = [this.firstBlock()]
}
firstBlock() {
const initblock = new Block();
initblock.index = 0;
initblock.preHash = "5de96e9f762a9120e4eb22b367630e9b1b7879bfa756d723302b0a30bace9443";
initblock.timestamp = new Date(2001, 4, 6).getTime();
initblock.data = ["this is the initblock"];
initblock.hash = "5de96e9f762a9120e4eb22b367630e9b1b7879bfa756d723302b0a30bace9443";
initblock.noce = 1;
return initblock;
}
}
2.定义创建新区块方法
创建区块需要传入需要打包的信息blockdata以及挖矿时算出的随机数nonce,其他信息可自动生成,通过block类的构造函数创建新区块。计算哈希值时需要导入crypto-js模块。const sha256 = require('crypto-js/sha256');
getLatestBlock() {
return this.chain[this.chain.length - 1]
}
createNewblock(blockdata, noce) {
const preBlock = this.getLatestBlock();
const index = (parseInt(preBlock.index) + 1).toString();
const nextTimeStamp = new Date().getTime();
const hash = sha256(index + blockdata + preBlock.hash + nextTimeStamp + noce).toString();
return new Block(index, preBlock.hash, nextTimeStamp, blockdata, hash, noce);
}
3.定义添加区块入链方法以及验证区块方法
验证区块的合法性包括验证区块的哈希值,索引值以及前一个区块的哈希值。通过验证的区块才会被加入区块链中。
isValidNewBlock(newBlock, preBlock) {
if (preBlock.hash !== newBlock.preHash) {
return false
}
if (parseInt(newBlock.index) !== parseInt(preBlock.index) + 1) {
return false
}
if (sha256(newBlock.index + newBlock.data + newBlock.preHash + newBlock.timestamp + newBlock.noce).toString() !== newBlock.hash) {
return false
}
return true
}
addBlock(newBlock) {
if (this.isValidNewBlock(newBlock, this.getLatestBlock())) {
this.chain.push(newBlock)
return true
}
return false
}
4.定义挖矿算法
通过对前区块的哈希值与当前打包数据加上一个随机数共同取哈希值,前五位为00000时打包成功,创建新区块并添加至区块链中。
mine(data) {
const preBlock = this.getLatestBlock();
let noce = 1;
while (true) {
if (sha256(preBlock.hash + data + noce).toString().substring(0, 5) !== '00000') {
noce++
} else {
this.addBlock(this.createNewblock(data, noce));
break;
}
}
}