JavaScript实现区块链(4)


最后,我们还需要更改一下 calculateHash() 函数。因为目前他还没有使用Nonce来计算hash。

calculateHash() {
 return SHA256(this.index +
 this.previousHash +
 this.timestamp +
 JSON.stringify(this.data) +
 this.nonce
 ).toString();
}

将它们结合在一起,你会得到如下所示的区块类:

class Block {
 constructor(index, timestamp, data, previousHash = '') {
 this.index = index;
 this.previousHash = previousHash;
 this.timestamp = timestamp;
 this.data = data;
 this.hash = this.calculateHash();
 this.nonce = 0;
 }
 calculateHash() {
 return SHA256(this.index + this.previousHash + this.timestamp + JSON.stringify(this.data) + this.nonce).toString();
 }
 mineBlock(difficulty) {
 while (this.hash.substring(0, difficulty) !== Array(difficulty + 1).join("0")) {
  this.nonce++;
  this.hash = this.calculateHash();
 }
 console.log("BLOCK MINED: " + this.hash);
 }
}

修改区块链

现在,我们的区块已经拥有Nonce并且可以被开采了,我们还需要确保我们的区块链支持这种新的行为。让我们先在区块链中添加一个新的属性来跟踪整条链的难度。我会将它设置为2(这意味着区块的hash必须以2个0开头)。

constructor() {
 this.chain = [this.createGenesisBlock()];
 this.difficulty = 2;
}

现在剩下要做的就是改变 addBlock() 方法,以便在将其添加到链中之前确保实际挖到该区块。下面我们将难度传给区块。

addBlock(newBlock) {
 newBlock.previousHash = this.getLatestBlock().hash;
 newBlock.mineBlock(this.difficulty);
 this.chain.push(newBlock);
}


大功告成!我们的区块链现在拥有了POW来抵御攻击了。

测试

现在让我们来测试一下我们的区块链,看看在POW下添加一个新区块会有什么效果。我将会使用之前的代码。我们将创建一个新的区块链实例然后往里添加2个区块。

let savjeeCoin = new Blockchain();
console.log('Mining block 1');
savjeeCoin.addBlock(new Block(1, "20/07/2017", { amount: 4 }));
console.log('Mining block 2');
savjeeCoin.addBlock(new Block(2, "20/07/2017", { amount: 8 }));

如果你运行了上面的代码,你会发现添加新区块依旧非常快。这是因为目前的难度只有2(或者你的电脑性能非常好)。

如果你创建了一个难度为5的区块链实例,你会发现你的电脑会花费大概十秒钟来挖矿。随着难度的提升,你的防御攻击的保护程度越高。

免责声明

就像之前说的:这绝不是一个完整的区块链。它仍然缺少很多功能(像P2P网路)。这只是为了说明区块链的工作原理。