工作量证明(Proof Of Work,POW)
Python例子
from itertools import count
from hashlib import md5
msg = 'randomstring'
for i in count():
hashid = md5((msg+str(i)).encode("utf-8")).hexdigest()
if hashid.startswith('0000000'):
print(i,hashid)
break
n = hashid
思考题:
- 如果搜索连续5个0开头的 hash 字符串,需要执行多少次 md5() 函数,耗时多少秒。
- 如果搜索连续6个0开头的 hash 字符串,需要执行多少次 md5() 函数,耗时多少秒。
- 如果搜索连续7个0开头的 hash 字符串,需要执行多少次 md5() 函数,耗时多少秒。
- 尝试从理论上估计不同数量0开头的hash字符串需要计算机最多执行多少次 md5() 函数。
从上至下依次为4,5,6,7个‘0’开头的测试结果。
从理论上估计不同数量(n)0开头的hash字符串需要计算机最多执行$16^n$次 md5() 函数。
因为不同数量(n)0开头的概率为$\frac{1}{16^n}$ ,当n = 8时 大概最多要执行4294967296次。
用JavaScript语言搭建一条区块链并实现工作量证明。
/*
* @Author: kok-s0s
* @Date: 2021-04-14 19:03:20
* @LastEditTime: 2021-04-14 20:45:18
* @Description: blockchain Proof of concept (概念验证) Proof of Work (工作量证明)
*/
// 区块链
// block
// chain
// data
// 之前区块的哈希值
// 自己的哈希值:是存储再区块里的信息 计算(data + 之前区块的哈希值)
const sha256 = require('crypto-js/sha256');
class Block {
constructor(data, previousHash) {
this.data = data;
this.previousHash = previousHash;
this.nonce = 1;
this.hash = this.computeHash();
}
computeHash() {
return sha256(this.data + this.previousHash + this.nonce).toString();
}
getAnswer(difficulty) {
// 开头前n位为0的Hash
let answer = ''
for (let i = 0; i < difficulty; i++) {
answer += '0';
}
return answer;
}
// 计算符合区块链难度要求的Hash
mine(difficulty) {
while (true) {
this.hash = this.computeHash();
if (this.hash.substring(0, difficulty) !== this.getAnswer(difficulty)) {
this.nonce++;
this.hash = this.computeHash();
} else {
break;
}
}
console.log('挖矿结束', this.hash);
}
}
// const block = new Block('转账100块', '123456')
// console.log(block)
class BlockChain {
constructor() {
this.chain = [this.bigBang()];
this.difficulty = 3;
}
// 生成祖先区块
bigBang() {
const genesisBlock = new Block('我是祖先', '');
return genesisBlock;
}
getLastestBlock() {
return this.chain[this.chain.length - 1];
}
// 添加区块到区块链上
addBlockToChain(newBlock) {
// data
// 找到最近一个block的Hash
// 这个Hash即新区快的previousHash
newBlock.previousHash = this.getLastestBlock().hash;
// newBlock.hash = newBlock.computeHash();
newBlock.mine(this.difficulty);
// Hash要满足工作量证明
this.chain.push(newBlock);
}
// 验证当前的区块链是否合法
// 当前数据是否有被篡改
// 区块的previousHash是否等于当前previous区块的Hash
validateChian() {
if (this.chain.length == 1) {
if (this.chain[0].hash !== this.chain[0].computeHash()) {
return false;
}
return true;
}
// 从第二区块开始验证
for (let i = 1; i <= this.chain.length - 1; i++) {
const blockRoValidate = this.chain[i];
// 当前的数据是否有被篡改
if (blockRoValidate.hash !== blockRoValidate.computeHash()) {
console.log("数据被篡改");
return false;
}
// 验证区块的previousHash是否等于previous区块的Hash
const previousBlock = this.chain[i - 1];
if (blockRoValidate.previousHash !== previousBlock.hash) {
console.log("前后区块断裂")
return false;
}
}
return true;
}
}
const chainTest = new BlockChain();
// console.log(chainTest);
// console.log(chainTest.validateChian());
const block1 = new Block('转账一千元', '');
chainTest.addBlockToChain(block1);
// console.log(chainTest);
const block2 = new Block('转账一元', '');
chainTest.addBlockToChain(block2);
console.log(chainTest);
// console.log(chainTest.validateChian())
// 尝试篡改区块
chainTest.chain[1].data = "kok-s0s";
chainTest.chain[1].mine(3);
console.log(chainTest.validateChian());
// chainTest.chain[1].data = '转账5元';
// chainTest.chain[1].hash = chainTest.chain[1].computeHash();
// console.log(chainTest.validateChian());