用python构建区块链(2)---工作量证明共识算法(proof of work)

mechanism.png

目录

用python构建区块链(1)---基本结构
用python构建区块链(2)---工作量证明共识算法(pow)

背景

  • 上一篇我们介绍了区块链的基本结构,今天我们在之前的基础上来简单实现一下工作量证明算法(proof of work),在介绍pow之前我们先思考一下为什么要工作量证明算法,或者再往前想一步为什么比特币如何解决信任的问题?
  • 比特币出现之前就有了拜占庭将军问题,主要思想是,如何在分布式系统环境里去相信其他人发给你的信息?下面是其描述:

一组拜占庭将军分别各率领一支军队共同围困一座城市。为了简化问题,将各支军队的行动策略限定为进攻或撤离两种。因为部分军队进攻部分军队撤离可能会造成灾难性后果,因此各位将军必须通过投票来达成一致策略,即所有军队一起进攻或所有军队一起撤离。因为各位将军分处城市不同方向,他们只能通过信使互相联系。在投票过程中每位将军都将自己投票给进攻还是撤退的信息通过信使分别通知其他所有将军,这样一来每位将军根据自己的投票和其他所有将军送来的信息就可以知道共同的投票结果而决定行动策略
系统的问题在于,将军中可能出现叛徒,他们不仅可能向较为糟糕的策略投票,还可能选择性地发送投票信息。假设有9位将军投票,其中1名叛徒。8名忠诚的将军中出现了4人投进攻,4人投撤离的情况。这时候叛徒可能故意给4名投进攻的将领送信表示投票进攻,而给4名投撤离的将领送信表示投撤离。这样一来在4名投进攻的将领看来,投票结果是5人投进攻,从而发起进攻;而在4名投撤离的将军看来则是5人投撤离。这样各支军队的一致协同就遭到了破坏。

拜占庭将军问题.png

比特币横空出世

  • 拜占庭将军问题主要问题是,中间人可以拦截消息,进行修改;上述的那些士兵可以理解成比特币中的一些节点,不是所有节点拿到消息后都是可以直接处理的,先去解决一个数学问题,就是工作量证明,只有拥有特定的计算能力解决了问题之后才能去修改或者校验(验证,打包,上链)。
工作量证明.png
  • 上图就是简单的工作量证明算法流程,一串数字后面有个x,x之前的数可以理解成交易数据,然后需要找到一个x,让整个数的hash值的开头有n个0,如果hash是很均匀的话,那么生成的hash值每一位为0或者1都是等可能的,所以前n个都为0的概率就是2的n次方/2的hash值位数,上图给出了如果hash值是5个bit的情况下的所有可能

渐入佳境

from hashlib import sha256
import time
class Block:
     
    def __init__(self,index,timestamp,data,previousHash=""):
        
        self.index = index
        self.timestamp = timestamp
        self.data = data
        self.previousHash = previousHash
        self.nonce = 0 //代表当前计算了多少次hash计算
        self.hash = self.calculateHash()
        
    
    def calculateHash(self):
        plainData = str(self.index)+str(self.timestamp)+str(self.data)+str(self.nonce)
        return sha256(plainData.encode('utf-8')).hexdigest()
    #挖矿 difficulty代表复杂度 表示前difficulty位都为0才算成功
    def minerBlock(self,difficulty):
        while(self.hash[0:difficulty]!=str(0).zfill(difficulty)):
            self.nonce+=1
            self.hash = self.calculateHash()
    
    def __str__(self):
        return str(self.__dict__)
    
    
class BlockChain:
    
    def __init__(self):
        self.chain = [self.createGenesisBlock()]
        self.difficulty = 5

    def createGenesisBlock(self):
        return Block(0,"01/01/2018","genesis block")
    
    def getLatestBlock(self):
        return self.chain[len(self.chain)-1]
    #添加区块前需要 做一道计算题😶,坐完后才能把区块加入到链上
    def addBlock(self,newBlock):
        newBlock.previousHash = self.getLatestBlock().hash
        newBlock.minerBlock(self.difficulty)
        self.chain.append(newBlock)
        
        
    
    def __str__(self):
        return str(self.__dict__)    
    
    def chainIsValid(self):
        for index in range(1,len(self.chain)):
            currentBlock = self.chain[index]
            previousBlock = self.chain[index-1]
            if (currentBlock.hash != currentBlock.calculateHash()):
                return False
            if previousBlock.hash != currentBlock.previousHash:
                return False
        return True
            
                  
myCoin = BlockChain()

# 下面打印了每个区块挖掘需要的时间 比特币通过一定的机制控制在10分钟出一个块 
# 其实就是根据当前网络算力 调整我们上面difficulty值的大小,如果你在
# 本地把上面代码difficulty的值调很大你可以看到很久都不会出计算结果
startMinerFirstBlockTime = time.time()
print("start to miner first block time :"+str(startMinerFirstBlockTime))

myCoin.addBlock(Block(1,"02/01/2018","{amount:4}"))

print("miner first block time completed" + ",used " +str(time.time()-startMinerFirstBlockTime) +"s")

startMinerSecondBlockTime = time.time()

print("start to miner first block time :"+str(startMinerSecondBlockTime))

myCoin.addBlock(Block(2,"03/01/2018","{amount:5}"))

print("miner second block time completed" + ",used " +str(time.time()-startMinerSecondBlockTime) +"s\n")

#print block info
print("print block info ####:\n")
for block in myCoin.chain:
    print("\n")
    print(block)
    
#check blockchain is valid
print("before tamper block,blockchain is valid ###")
print(myCoin.chainIsValid())

#tamper the blockinfo
myCoin.chain[1].data = "{amount:1002}"
print("after tamper block,blockchain is valid ###")
print(myCoin.chainIsValid())

习以为常

start to miner first block time :1524652057.52226
miner first block time completed,used 2.3928141593933105s
start to miner first block time :1524652059.915224
miner second block time completed,used 1.791139841079712s

print block info ####:

{'index': 0, 'timestamp': '01/01/2018', 'data': 'genesis block', 'previousHash': '', 'nonce': 0, 'hash': '1fb6344a6e5c8f0c7e03e1ded0e831a3d92c3741eb5f7153405b6107e3d8164b'}

{'index': 1, 'timestamp': '02/01/2018', 'data': '{amount:4}', 'previousHash': '1fb6344a6e5c8f0c7e03e1ded0e831a3d92c3741eb5f7153405b6107e3d8164b', 'nonce': 767597, 'hash': '000004c911b7d620a648fd8cec12d2d1cbe838c427f8cb2e12f00eaf64ffe1d3'}

{'index': 2, 'timestamp': '03/01/2018', 'data': '{amount:5}', 'previousHash': '000004c911b7d620a648fd8cec12d2d1cbe838c427f8cb2e12f00eaf64ffe1d3', 'nonce': 576083, 'hash': '00000b72782457590c470f83d574438b5bad3d8eb971e9f3e5d2a041107f8db3'}
before tamper block,blockchain is valid ###
True
after tamper block,blockchain is valid ###
False

推荐阅读更多精彩内容