赞
踩
交易包括了发送者,接受者,交易金额以及数字签名,为了简化,这里除了交易金额都用下标代替(节点列表中节点的下标),代码如下:
class Transaction: def __init__(self, sender_id: int, recipient_id: int, amounts: float, signature: int = -1): # 为简化,这里的id均为节点列表的下标, 数字签名也是, 实际数字签名会采用加密算法 self._sender_id = sender_id self._recipient_id = recipient_id self._amounts = amounts self._signature = signature @property def sender_id(self): return self._sender_id @sender_id.setter def sender_id(self, value: int): self._sender_id = value @property def recipient_id(self): return self._recipient_id @recipient_id.setter def recipient_id(self, value: int): self._recipient_id = value @property def amounts(self): return self._amounts @amounts.setter def amounts(self, value: float): self._amounts = value @property def signature(self): return self._signature @signature.setter def signature(self, value: int): self._signature = value
交易池用于存放交易,并且在创建新区块的时候从中取出部分交易作为新区块中包含的交易,可以使用队列模拟,这里是为了简化,在实际应用中一般会先选交易额大的或采用其他逻辑,而不是先进先出,代码如下:
class TransactionPool: def __init__(self): self._transaction_queue = queue.Queue() def add_transaction(self, new_transaction): self._transaction_queue.put(new_transaction) def get_transaction(self) -> Union[Transaction, None]: if not self._transaction_queue.empty(): return self._transaction_queue.get() else: return None @property def transaction_queue(self): return self._transaction_queue @transaction_queue.setter def transaction_queue(self, value): self._transaction_queue = value
区块包含了区块在区块链中的下标,上一个区块的哈希值,当前区块的哈希值,以及一系列交易,一般还需要有一个用于计算当前区块哈希值的一个时间戳。在初始情况下,还需要有一个创世区块,代码如下:
class Block: def __init__(self, index: int, previous_block_hash: str, transaction_list: List['Transaction'], time_stamp: datetime.datetime = datetime.datetime.now(), block_hash: str = '' ): self._index = index self._previous_block_hash = previous_block_hash self._transaction_list = transaction_list self._time_stamp = time_stamp self._block_hash = block_hash def _set_hash(self, block_hash: str): self._block_hash = block_hash @property def index(self): return self._index @index.setter def index(self, value): self._index = value @property def previous_block_hash(self): return self._previous_block_hash @previous_block_hash.setter def previous_block_hash(self, value): self._previous_block_hash = value @property def block_hash(self): return self._block_hash @block_hash.setter def block_hash(self, value): self._block_hash = value @property def transaction_list(self): return self._transaction_list @transaction_list.setter def transaction_list(self, value): self._transaction_list = value @property def time_stamp(self): return self._time_stamp @time_stamp.setter def time_stamp(self, value): self._time_stamp = value # 创世区块 @staticmethod def create_genesis_block(): time_stamp = datetime.datetime.now() header_bin = str(time_stamp) return Block(0, '0', [], time_stamp, hashlib.sha256(header_bin.encode()).hexdigest())
编写节点类前,先完成几个简单的函数,分别是验证哈希是否符合结构、验证区块链结构合法以及交易是否合法,都是完成简单的功能,验证交易是否合法函数会用到节点类,所以先会报错,可以不用管,代码如下:
# 验证哈希值(简化版, 只验证是否符合SHA-256哈希值) def verify_hash_code(hash_str: str) -> bool: if len(hash_str) != 64: return False pattern = re.compile(r'^[a-f0-9]{64}$') return bool(pattern.match(hash_str)) # 验证区块链结构合法(简化版) def structure_legal(block: Block) -> bool: if block.index < 0: return False if len(block.transaction_list) == 0: return False if not verify_hash_code(block.block_hash): return False if not verify_hash_code(block.previous_block_hash): return False return True # 验证交易是否合法(简化版, 只看发送人余额是否则足够、数字签名是否合法) def transaction_legal(transaction: Transaction, node_list: List['Node']) -> bool: # 签名是否合法 if transaction.signature < 0: return False # 发送人余额是否足够 if node_list[transaction.sender_id].balance < transaction.amounts: return False return True
然后再编写节点类,节点包括名称、余额、每个节点维护的区块链以及节点的id,节点的功能包括添加区块、验证新区块以及挖矿三个操作,添加区块只需要往list中append就可以了,验证新区块主要包含验证区块结构、交易以及连续性是否合法,可以利用上面的三个函数完成,而挖矿则是从交易池中挑选交易生成新的区块,共识机制使用简化版的工作量证明(也可以用最简单的最长链规则,认为最长的链就是正确的),代码如下:
class Node: def __init__(self, name: str, balance: float = 0., blockchain: List['Block'] = None, node_id: int = -1): self._name = name self._balance = balance if blockchain is None: self._blockchain = [] else: self._blockchain = blockchain self._node_id = node_id self._signature = self._node_id def _add_block(self, new_block): self._blockchain.append(new_block) # 验证新区块(简化版) def _verify_block(self, new_block: Block, node_list: List['Node']) -> bool: # 验证区块结构合法 if not structure_legal(new_block): print(new_block.block_hash) return False # 验证交易是否合法 for transaction in new_block.transaction_list: if not transaction_legal(transaction, node_list): return False # 验证新区块的连续性(与上一个区块的哈希值是否相同) if not self.blockchain[-1].block_hash == new_block.previous_block_hash: return False return True # 共识机制使用工作量证明(PoW) def _mining(self, transaction_pool: TransactionPool, node_list: List['Node']) -> Union[Block, None]: # 从交易池中取出所有交易 # 一般不会取出所有的交易,矿工可以基于自己的策略和目标选择交易,而且区块大小也有限制,这里做简化,假设每次挖矿都选择交易池中所有的交易 transaction_list = [] while not transaction_pool.transaction_queue.empty(): transaction_list.append(transaction_pool.get_transaction()) # 计算新区块的哈希值 # 这里会进行一个非常耗时的计算得到哈希值,这里简化直接对上一个区块的哈希值和交易列表以及时间戳做sha256哈希编码 time_stamp = datetime.datetime.now() header_bin = str(self.blockchain[-1].block_hash) + str(transaction_list) + str(time_stamp) new_hash = hashlib.sha256(header_bin.encode()).hexdigest() # 创建新的区块 new_block = Block(len(self.blockchain), self.blockchain[-1].block_hash, transaction_list, time_stamp, new_hash) # 广播每个节点进行验证 # 这里简化只执行一次,实际上每个节点都会验证,当大多数节点验证通过才会通过 if self._verify_block(new_block, node_list): self._balance = self._balance + 10 # 矿工奖励 return new_block else: return None def add_block(self, new_block): self._add_block(new_block) def mining(self, transaction_pool: TransactionPool, node_list: List['Node']) -> Union[Block, None]: return self._mining(transaction_pool, node_list) @property def name(self): return self._name @name.setter def name(self, value): self._name = value @property def balance(self): return self._balance @balance.setter def balance(self, value): self._balance = value @property def blockchain(self): return self._blockchain @blockchain.setter def blockchain(self, value): self._blockchain = value @property def node_id(self): return self._node_id @node_id.setter def node_id(self, value): self._node_id = value @property def signature(self): return self._signature @signature.setter def signature(self, value): self._signature = value
这里为简化就在主函数中写面向过程的函数了,可以改成社区类或者其他类完成整个流程:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。