import datetime
import hashlib
import json
import requests
class Blockchain:
def __init__(self):
self.chain = [] # 主链
self.nodes = set() # 节点列表
self.current_tranactions = [] # 交易信息
# 创世区块创建
self.new_block(proof=100, pre_hash=1)
def new_block(self, proof, pre_hash=None):
"""
生成新的区块
"""
block = {
'index': len(self.chain)+1, # 区块高度
'timestamp': datetime.datetime.now(), # 创建区块的时间
'transactions': self.current_tranactions, # 区块包含的交易信息
'proof': proof, # 打包区块的工作量证明
'pre_hash': pre_hash or self.hash(self.chain[-1]), # 上以区块的hash
}
self.current_tranactions = []
self.chain.append(block) # 添加到主链
@staticmethod
def hash(block):
"""
计算区块hash
"""
block_str = json.dumps(block, sort_keys=True).encode('utf-8')
return hashlib.sha256(block_str).hexdigest()
def new_transaction(self, sender, receiver, amount):
"""
创建一条新的交易(也可是其他信息)
"""
transactoin = {
'sender': sender, # 发送方
'receiver': receiver, # 接收方
'amount': amount, # 金额
}
self.current_tranactions.append(transactoin) # 追加交易信息
return self.last_block['index'] + 1
@property
def last_block(self):
"""
获取主链中最后一个区块信息
"""
return self.chain[-1]
def proof_of_work(self, last_block):
"""
计算工作量证明(俗称挖矿)
"""
last_proof = last_block['proof']
last_hash = self.hash(last_block)
proof = 0
# 穷举上一个区块工作量和当前区块工作量和上一区块hash所生成的哈希值直至hash前六位为'000000'即为有效工作量。
# 通过改变这一条件,可以调整难度。在区块链中有动态调节机制,保证平均10分钟左右生成一个区块。
while self.valid_proof(last_proof, proof, last_hash) is False:
proof += 1
return proof
@staticmethod
def valid_proof(last_proof, proof, last_hash):
"""
验证工作量证明
"""
guess = f'{last_proof}{proof}{last_hash}'.encode('utf-8')
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:6] == '000000'
def resolve_conflicts(self):
"""
检查区块链冲突
此函数会遍历其相邻节点寻找更长的区块链,如果发现更长的区块链则取代当前节点的区块链
"""
neighbours = self.nodes
new_chain = None
max_length = len(self.chain)
# 遍历相连节点逐一验证
for node in neighbours:
response = requests.get(f'http://{node}/chain')
if response.status_code == 200:
length = response.json()['length']
chain = response.json()['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
else:
return False
def valid_chain(self, chain):
"""
验证区块链是否合法
"""
last_block = chain[0]
current_index = 1
while current_index < len(chain):
block = chain[current_index]
# 验证上以区块存储的hash值是否等于区块计算出的hash值
if block['pre_hash'] != self.hash(last_block):
return False
# 验证当前区块工作量证明是否有效
if not self.valid_proof(last_block['proof'], block['proof'], block['pre_hash']):
return False
last_block = block
current_index += 1
return True