通过写一个区块链原型程序学习区块链
网上看到一篇翻译文章:
https://learnblockchain.cn/2017/10/27/build_blockchain_by_python/
学习一门技术最好的方法就是自己做一个,水平有限,手敲了一遍这个代码,边敲边学,在这个过程中对区块链有了更加全面的认识,同时也学习了一些python知识。
区块链基本概念
区块链是一个分布式账本,每个参与挖矿的节点共同保存全部交易信息,没有中心化认证机构,全网半数以上节点存活就可以保证交易信息正确有效。
下面通过这个原型演示程序介绍一些区块链的基本概念
1. 区块(block):
相对完整的区块包含区块头和区块体,区块头保存区块的元数据,区块体的内容是交易信息记录,区块头中包含交易信息的Merkle树哈希,这个原型程序没有区块体,直接将区块的元数据和交易信息一起保存在区块里。
· 索引:区块序号
· 时间戳:区块生成的时间
· 工作量证明:生成这个区块耗费的工作量的证明
· 前一个区块的哈希:为了保证整个链条的合法性不被篡改,每个区块保存前一个区块的哈希值
本程序区块:
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'proof': proof,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
2. 区块链(blockchain):
矿工通过挖矿把一段时间内的交易信息固化在区块内,每个区块通过在本区块存储上一个区块的哈希值形成联结关系,就像一条贪吃蛇,不断生成区块形成链条,就是区块链了。
ew_block(self, proof, previous_hash=None): """ 生成一个新块,添加进链 :param proof:工作量算法给出的工作量证明 :param previous_hash: (optional) block = { 'index': len(self.chain) + 1, 'timestamp': time(), 'transactions': self.current_transactions, 'proof': proof, 'previous_hash': previous_hash or self.hash(self.chain[-1]), } # 重置交易列表 self.current_transactions = [] self.chain.append(block) return block前一个块的哈希值 :return: 新块 """
3. 交易信息(transaction):
区块链应用的目的是维护一个账本,也就是交易记录,比如谁什么时间给了谁多少钱。
def new_transaction(self, sender, recipient, amount): """ 生成新交易信息,信息将加入到下一个待挖的区块中 :param sender:发送者地址 :param recipient: self.current_transactions.append({ 'sender': sender, 'recipient': recipient, 'amount': amount, }) return self.last_block['index'] + 1接收者地址 :param amount: 交易额 :return: 记录这笔交易的块的索引 """
4. 挖矿(mine):
交易随时随刻在发生,交易发生后交易信息广播给在区块链程序里注册的每一个矿工,矿工通过挖矿工作生成区块,矿工挖矿的目的就是封存交易信息,只有新的区块挖出来以后交易信息才最终得到确认。挖矿需要消耗一定的时间,比特币的规定时间是10分钟,挖矿成功的时候,把从上一个区块生成开始到挖出这个区块的时间点之间(10分钟)的交易信息封存在这个新挖出的区块里,连进区块链,并把交易记录清零。因为挖矿需要耗费时间和设备以及电力资源,挖出区块的矿工会得到奖励,矿工提供了工作量证明就能得到奖励。
def mine(): # 计算工作量证明 last_block = blockchain.last_block last_proof = last_block['proof'] proof = blockchain.proof_of_work(last_proof) # 给工作量证明的节点提供奖励 # 发送者为0表示是新挖出的币 blockchain.new_transaction( sender=0, recipient=node_identifier, amount=1, ) # 将新block加入chain block = blockchain.new_block(proof)
5. 工作量证明(POW):
proof of work,挖矿的工足量证明是通过计算一个字符串哈希值,使这个哈希值满足一定的条件。这个字符串由前一个区块的工作量证明和一个随机数组成,由于哈希算法是单向加密,因此只能通过不断地试不同的随机数来使组合字符串的哈希值满足条件,通过对这个条件的苛刻程度进行调整可以控制挖矿的效率,即多长时间挖出一个区块。比特币使用sha256哈希算法计算工作量,本程序的POW条件为哈希值前4位为0。
@staticmethod def proof_of_work(last_proof): """ 工作量证明: - 查找一个p'使得hash(pp')以4个0开头 - p是上一个块的proof,p’是当前的proof :param last_proof::return: proof = 0 while hashlib.sha256(f'{last_proof}{proof}'.encode()).hexdigest()[:4] != '0000': proof += 1 return proof"""
6. 分叉冲突(conflict)
每个矿工在自己的链尾添加新区块,为了解决分布式系统的一致性问题,要解决分叉冲突。本程序每个矿工维护自己的链,解决冲突的方法是手工轮训每个矿工维护的链,找到最长链,如果比自己的链长,就把自己的链替换为这个最长链。
def resolve_conflicts(self): """ 共识算法解决冲突 使用网络中最长的链 :return:True如果链被取代,否则为False """ neighbours = self.nodes new_chain = None max_length = len(self.chain) # 抓取并验证网络中所有节点的链 for node in neighbours: response = requests.get(f'http://{node}/chain') print(node) if response.status_code == 200: length = response.json()['length'] chain = response.json()['chain'] print(length) print(chain) print(self.valid_chain(chain)) # 检查链的长度是否更长,链是否合法 if length > max_length and self.valid_chain(chain): max_length = length new_chain = chain # 如果发现了新的合法的更长的链就用它替换我的链 if new_chain: self.chain = new_chain return True return False
区块链运行机制
本程序使用python flask框架实现web接口,作为一个原型演示程序实现了如下功能:
1. 当有新的矿工节点加入工作网络,它把其他节点注册进自己的节点列表并把自己注册到其他全部矿工节点
2. 各节点可以随时添加交易信息,不过本程序未实现交易信息的广播
3. 矿工挖矿生成新区块添加进自己的链
4. 轮训查找最长链替换自己的链
功能演示
在80节点注册81和82节点
在81节点添加交易信息
在81节点挖矿
在80节点解决冲突,链条被替换为81节点的链条
在82节点注册80和81节点
在82节点解决冲突,链条被替换为最长链
本程序可以扩充的简单功能
程序代码及运行方法
代码放在github,建议使用docker运行
https://github.com/YngwieWang/blockchain