pow 机制
1.哈希函数的特点
说到 pow 机制,就离不开哈希函数,哈希函数具有以下特点:
- 输入长度不固定,输出长度固定
- 输入不同,输出不同
- 输入相同,输出相同
- 不可逆
- 雪崩效应
雪崩效应:输入变量中只要有一点变化,输出就会发生巨大变化
const CryptoJS = require("crypto-js");
let mseeage1 = "heibaihui";
let mseeage2 = "heibaihu1";
console.log("mseeage1的哈希:" + CryptoJS.SHA256(mseeage1));
console.log("mseeage2的哈希:" + CryptoJS.SHA256(mseeage2));
运行结果如下:
我们可以看到我们只是修改了 mseeage2 的最后一个字符,但是哈希值却发生了巨大变化,这就是哈希函数的雪崩效应
2.实现 pow 机制
pow 机制就是通过哈希函数来生成一个哈希值,这个哈希值需要满足以下条件:
- 哈希值的前 n 位为 0
- 哈希值需要通过不断尝试来生成,直到满足条件为止
注意:哈希函数的输入是任意的,所以我们可以通过改变输入来生成不同的哈希值,直到满足条件为止
同时,比特币的 pow 机制中,n 的值是动态变化的,真正的挖矿就是通过不断尝试来生成满足条件的哈希值,然后通过这个哈希值来生成新的区块,而我们为了简化,n 的值是固定的
现在我们有一个需求,我们需要生成一个哈希值,这个哈希值的前 n 位为 0,n 的值为 3,计算出来的就可以获得计账权.
const CryptoJS = require("crypto-js");
const message = "heibaihui";
const logo = "0000";
const pow = (logo, message) => {
let nonce = 0;
const start = Date.now();
while (true) {
const hash = CryptoJS.SHA256(message + nonce).toString();
if (hash.startsWith(logo)) {
const end = Date.now();
console.log(`找到满足条件的 nonce:${nonce}`);
console.log(`对应的哈希值:${hash}`);
console.log(`耗时:${(end - start) / 1000} 秒`);
break;
}
nonce++;
}
};
pow(logo, message);
运行结果如下:
在这里我们通过不断尝试来生成满足条件的哈希值,直到找到满足条件的哈希值为止,然后输出这个哈希值和对应的 nonce 值,以及计算出来的时间,这就是 pow 机制的基本原理.
在比特币中,平均每 10 分钟产生一个新区块。
比特币网络通过调整挖矿难度来维持这个平均出块时间。如果全网算力增加,挖矿难度会相应提高,使得找到有效区块的时间仍然保持在大约 10 分钟左右;如果算力减少,难度会降低,以确保出块时间不会过长。
这个相对稳定的出块时间对于比特币网络的安全性和一致性非常重要。它既保证了交易的确认速度不会太慢,又使得攻击者难以篡改区块链,因为要重新计算一个区块以及后续的所有区块需要巨大的算力和时间。
接下来,我们就要修改 Block 类和 BlockChain 类,让他们可以保证新区块的创建有条件.确保出块时间.
修改 Block 类和 BlockChain 类
Block 类
// 定义一个区块类
export class Block {
public data: string;
public previousHash: string;
public hash: string;
public nonce: number;
constructor(data: string, previousHash: string) {
this.data = data;
this.previousHash = previousHash;
this.nonce = 0;
this.hash = this.calculateHash();
}
// 计算哈希
calculateHash(): string {
return CryptoJS.SHA256(
this.previousHash + this.data + this.nonce
).toString();
}
getAnswer(difficulty: number): string {
let answer = "";
for (let i = 0; i < difficulty; i++) {
answer += "0";
}
return answer;
}
mine(difficulty: number): void {
const start = Date.now();
while (true) {
this.hash = this.calculateHash();
if (this.hash.substring(0, difficulty) !== this.getAnswer(difficulty)) {
this.nonce++;
this.hash = this.calculateHash();
} else {
const end = Date.now();
console.log("挖矿成功,区块哈希值为:" + this.hash);
console.log(`一共计算了: ${this.nonce}次`);
console.log(`耗时:${(end - start) / 1000} 秒`);
break;
}
}
}
}
BlockChain 类
// 定义一个区块链类
export class Blockchain {
public chain: Block[];
public difficulty: number;
constructor() {
this.chain = [this.createGenesisBlock()];
// 设置挖矿难度
this.difficulty = 4;
}
// 创世区块的创建
createGenesisBlock(): Block {
return new Block("创世区块", "");
}
// 获取最后一个区块
getLastBlock(): Block {
return this.chain[this.chain.length - 1];
}
// 区块的追加
pushLatestBlock(newBlock: Block): void {
newBlock.previousHash = this.getLastBlock().hash;
// newBlock.hash = newBlock.calculateHash();
newBlock.mine(this.difficulty);
this.chain.push(newBlock);
}
// 链的校验
isChainValid(): boolean {
for (let i = 1; i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
// 校验区块的 hash 值
if (currentBlock.hash !== currentBlock.calculateHash()) {
console.log("当前区块的哈希值与计算出的哈希值不一致");
return false;
}
// 校验区块链接是否正常
if (currentBlock.previousHash !== previousBlock.hash) {
console.log("当前区块的 previousHash 与前一个区块的 hash 不一致");
return false;
}
}
return true;
}
}
main.ts
// 创建一个区块
const block1 = new Block("转账10个代币给张三", "1");
// 创建一个区块链
const blockchain1 = new Blockchain();
// 将区块添加到区块链中
blockchain1.pushLatestBlock(block1);
console.log(blockchain1.isChainValid());
console.log(blockchain1);
运行结果如下:
如图所示,我们成功创建了一个区块,并将其添加到区块链中,同时校验了区块链的完整性。并且,我们还实现了简易区块的哈希值计算和pow机制,使得区块链更加安全可靠。