查看“︁构建自己的区块链”︁的源代码
←
构建自己的区块链
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
== 如何构建自己的区块链:Python 教程 == 本教程将引导您从零开始构建区块链的基础知识。通过一个具体示例的详细讲解,您将更深入地了解区块链的优势和局限性。如需更全面的概述,我推荐您阅读 BitsOnBlocks 上的[https://bitsonblocks.net/2015/09/09/gentle-introduction-blockchain-technology/ 这篇优秀文章]。 === 1. 交易、验证和系统状态更新 === 区块链本质上是一个分布式数据库,它有一套规则来验证数据库中新增的数据。我们将首先追踪两个虚拟人物——爱丽丝和鲍勃——的账户,他们将彼此进行虚拟货币交易。 我们需要创建一个用于存储传入交易的交易池,验证这些交易,并将它们打包成一个区块。 我们将使用哈希函数为每笔交易创建一个“指纹”——这个哈希函数将每个区块彼此关联起来。为了方便使用,我们将定义一个辅助函数来封装我们使用的 Python 哈希函数。<syntaxhighlight lang="python3" line="1"> import hashlib, json, sys def hashMe(msg=""): # For convenience, this is a helper function that wraps our hashing algorithm if type(msg)!=str: msg = json.dumps(msg,sort_keys=True) # If we don't sort keys, we can't guarantee repeatability! if sys.version_info.major == 2: return unicode(hashlib.sha256(msg).hexdigest(),'utf-8') else: return hashlib.sha256(str(msg).encode('utf-8')).hexdigest() </syntaxhighlight>接下来,我们要创建一个函数来生成 Alice 和 Bob 之间的交易。我们将用负数表示取款,用正数表示存款。我们将确保交易始终发生在我们系统的两个用户之间,并且存款金额与取款金额大小相等——也就是说,我们既不创造货币,也不销毁货币。<syntaxhighlight lang="python3" line="1"> import random random.seed(0) def makeTransaction(maxValue=3): # This will create valid transactions in the range of (1,maxValue) sign = int(random.getrandbits(1))*2 - 1 # This will randomly choose -1 or 1 amount = random.randint(1,maxValue) alicePays = sign * amount bobPays = -1 * alicePays # By construction, this will always return transactions that respect the conservation of tokens. # However, note that we have not done anything to check whether these overdraft an account return {u'Alice':alicePays,u'Bob':bobPays} </syntaxhighlight>现在让我们创建大量交易,然后将它们分成区块。 txnBuffer = [makeTransaction() for i in range(30)] 下一步:创建我们自己的区块!我们将从交易缓冲区中取出前 k 笔交易,并将它们打包成一个区块。在此之前,我们需要定义一个方法来检查我们提取到区块中的交易的有效性。对于比特币,验证函数会检查输入值是否为有效的未花费交易输出(UTXO),交易输出是否不大于输入值,以及用于签名的密钥是否有效。在以太坊中,验证函数会检查智能合约是否被忠实执行并遵守 gas 限制。 不过别担心,我们不必构建如此复杂的系统。我们将定义一套非常简单的规则,这些规则适用于基本的代币系统: * 存款和取款的总和必须为 0(代币既不被创造也不被销毁) * 用户账户必须有足够的资金来支付任何提款。 如果违反了其中任何一个条件,我们将拒绝交易。 同时提供了一些交易示例,其中一些是欺诈性的——但我们现在可以检查它们的有效性!<syntaxhighlight lang="python3" line="1"> def updateState(txn, state): # Inputs: txn, state: dictionaries keyed with account names, holding numeric values for transfer amount (txn) or account balance (state) # Returns: Updated state, with additional users added to state if necessary # NOTE: This does not not validate the transaction- just updates the state! # If the transaction is valid, then update the state state = state.copy() # As dictionaries are mutable, let's avoid any confusion by creating a working copy of the data. for key in txn: if key in state.keys(): state[key] += txn[key] else: state[key] = txn[key] return state def isValidTxn(txn,state): # Assume that the transaction is a dictionary keyed by account names # Check that the sum of the deposits and withdrawals is 0 if sum(txn.values()) is not 0: return False # Check that the transaction does not cause an overdraft for key in txn.keys(): if key in state.keys(): acctBalance = state[key] else: acctBalance = 0 if (acctBalance + txn[key]) < 0: return False return True state = {u'Alice':5,u'Bob':5} print(isValidTxn({u'Alice': -3, u'Bob': 3},state)) # Basic transaction- this works great! True print(isValidTxn({u'Alice': -4, u'Bob': 3},state)) # But we can't create or destroy tokens! False print(isValidTxn({u'Alice': -6, u'Bob': 6},state)) # We also can't overdraft our account. False print(isValidTxn({u'Alice': -4, u'Bob': 2,'Lisa':2},state)) # Creating new users is valid. True print(isValidTxn({u'Alice': -4, u'Bob': 3,'Lisa':2},state)) # But the same rules still apply! False </syntaxhighlight>每个区块包含一批交易、指向前一个区块哈希值的引用(如果区块编号大于 1)以及其内容和区块头的哈希值。 === 2. 构建区块链:从交易到区块 === 我们准备开始构建区块链!目前区块链上什么都没有,但我们可以通过定义“创世区块”(系统中的第一个区块)来启动它。由于创世区块不与任何先前的区块关联,它的处理方式略有不同,我们可以任意设置系统状态。在本例中,我们将为两位用户(Alice 和 Bob)创建账户,并分别给予他们 50 个代币。<syntaxhighlight lang="python3" line="1"> state = {u'Alice':50, u'Bob':50} # Define the initial state genesisBlockTxns = [state] genesisBlockContents = {u'blockNumber':0,u'parentHash':None,u'txnCount':1,u'txns':genesisBlockTxns} genesisHash = hashMe( genesisBlockContents ) genesisBlock = {u'hash':genesisHash,u'contents':genesisBlockContents} genesisBlockStr = json.dumps(genesisBlock, sort_keys=True) </syntaxhighlight>这将成为所有其他要素联系在一起的第一个要素。 <span lang="zh-Hans-CN" dir="ltr">chain = [genesisBlock]</span> 对于每个区块,我们希望收集一组交易信息,创建区块头,对其进行哈希处理,然后将其添加到链中。<syntaxhighlight lang="python3" line="1"> def makeBlock(txns,chain): parentBlock = chain[-1] parentHash = parentBlock[u'hash'] blockNumber = parentBlock[u'contents'][u'blockNumber'] + 1 txnCount = len(txns) blockContents = {u'blockNumber':blockNumber,u'parentHash':parentHash, u'txnCount':len(txns),'txns':txns} blockHash = hashMe( blockContents ) block = {u'hash':blockHash,u'contents':blockContents} return block </syntaxhighlight>让我们用这个方法将交易缓冲区处理成一组数据块:<syntaxhighlight lang="python3" line="1"> blockSizeLimit = 5 # Arbitrary number of transactions per block- # this is chosen by the block miner, and can vary between blocks! while len(txnBuffer) > 0: bufferStartSize = len(txnBuffer) ## Gather a set of valid transactions for inclusion txnList = [] while (len(txnBuffer) > 0) & (len(txnList) < blockSizeLimit): newTxn = txnBuffer.pop() validTxn = isValidTxn(newTxn,state) # This will return False if txn is invalid if validTxn: # If we got a valid state, not 'False' txnList.append(newTxn) state = updateState(newTxn,state) else: print("ignored transaction") sys.stdout.flush() continue # This was an invalid transaction; ignore it and move on ## Make a block myBlock = makeBlock(txnList,chain) chain.append(myBlock) </syntaxhighlight>链信息输出如下:<syntaxhighlight lang="json" line="1"> chain[0] { 'contents': {'blockNumber': 0, 'parentHash': None, 'txnCount': 1, 'txns': [{'Alice': 50, 'Bob': 50}]}, 'hash': '7c88a4312054f89a2b73b04989cd9b9e1ae437e1048f89fbb4e18a08479de507' } chain[1] { 'contents': { 'blockNumber': 1, 'parentHash': '7c88a4312054f89a2b73b04989cd9b9e1ae437e1048f89fbb4e18a08479de507', 'txnCount': 5, 'txns': [{'Alice': 3, 'Bob': -3}, {'Alice': -1, 'Bob': 1}, {'Alice': 3, 'Bob': -3}, {'Alice': -2, 'Bob': 2}, {'Alice': 3, 'Bob': -3}] }, 'hash': '7a91fc8206c5351293fd11200b33b7192e87fad6545504068a51aba868bc6f72' } </syntaxhighlight>正如预期的那样,创世区块包含一笔无效交易,该交易会初始化账户余额(凭空创建代币)。子区块引用了父区块的哈希值,其中包含一组影响系统状态的新交易。现在我们可以看到系统状态已更新,包含了这些交易。 === 3 检查链有效性 === 既然我们已经知道如何创建新区块并将它们连接成链,那么让我们定义一些函数来检查新区块是否有效,以及整个链是否有效。 在区块链网络中,这一点在两个方面变得尤为重要: * 在初始设置节点时,我们会下载完整的区块链历史记录。下载完成后,我们需要遍历整个区块链来计算系统状态。为了防止有人在初始链中插入无效交易,我们需要在初始下载时检查整条链的有效性。 * 一旦我们的节点与网络同步(拥有最新的区块链副本和系统状态的表示),它就需要检查广播到网络的新区块的有效性。 我们需要三个功能来实现这一点: * '''checkBlockHash''': 一个简单的辅助函数,用于确保区块内容与哈希值匹配。 * '''checkBlockValidity''': 检查给定父节点和当前系统状态的区块的有效性。如果区块有效,我们希望它返回更新后的状态;否则,抛出错误。 * '''checkChain''': 检查整个区块链的有效性,并计算从创世区块开始的系统状态。如果区块链有效,则返回系统状态;否则,抛出错误。 <syntaxhighlight lang="python3" line="1"> def checkBlockHash(block): # Raise an exception if the hash does not match the block contents expectedHash = hashMe( block['contents'] ) if block['hash']!=expectedHash: raise Exception('Hash does not match contents of block %s'% block['contents']['blockNumber']) return def checkBlockValidity(block,parent,state): # We want to check the following conditions: # - Each of the transactions are valid updates to the system state # - Block hash is valid for the block contents # - Block number increments the parent block number by 1 # - Accurately references the parent block's hash parentNumber = parent['contents']['blockNumber'] parentHash = parent['hash'] blockNumber = block['contents']['blockNumber'] # Check transaction validity; throw an error if an invalid transaction was found. for txn in block['contents']['txns']: if isValidTxn(txn,state): state = updateState(txn,state) else: raise Exception('Invalid transaction in block %s: %s'%(blockNumber,txn)) checkBlockHash(block) # Check hash integrity; raises error if inaccurate if blockNumber!=(parentNumber+1): raise Exception('Hash does not match contents of block %s'%blockNumber) if block['contents']['parentHash'] != parentHash: raise Exception('Parent hash not accurate at block %s'%blockNumber) return state def checkChain(chain): # Work through the chain from the genesis block (which gets special treatment), # checking that all transactions are internally valid, # that the transactions do not cause an overdraft, # and that the blocks are linked by their hashes. # This returns the state as a dictionary of accounts and balances, # or returns False if an error was detected ## Data input processing: Make sure that our chain is a list of dicts if type(chain)==str: try: chain = json.loads(chain) assert( type(chain)==list) except: # This is a catch-all, admittedly crude return False elif type(chain)!=list: return False state = {} ## Prime the pump by checking the genesis block # We want to check the following conditions: # - Each of the transactions are valid updates to the system state # - Block hash is valid for the block contents for txn in chain[0]['contents']['txns']: state = updateState(txn,state) checkBlockHash(chain[0]) parent = chain[0] ## Checking subsequent blocks: These additionally need to check # - the reference to the parent block's hash # - the validity of the block number for block in chain[1:]: state = checkBlockValidity(block,parent,state) parent = block return state </syntaxhighlight> === 4 整合:最终的区块链架构 === 在实际的区块链网络中,新节点会下载区块链副本并进行验证(就像我们刚才做的那样),然后在点对点网络上宣告自身的存在,并开始监听交易。它们将交易打包成一个区块,然后将自己提议的区块传递给其他节点。 我们已经了解了如何验证区块链副本,以及如何将交易打包成一个区块。如果我们从其他地方收到一个区块,验证它并将其添加到我们自己的区块链中也很容易。 假设以下代码在节点 A 上运行,该节点负责挖矿:<syntaxhighlight lang="python3" line="1"> import copy nodeBchain = copy.copy(chain) nodeBtxns = [makeTransaction() for i in range(5)] newBlock = makeBlock(nodeBtxns,nodeBchain) </syntaxhighlight>现在假设 <code>newBlock</code> 被发送到我们的节点,我们想要检查它是否为有效区块,如果是则更新我们的状态:<syntaxhighlight lang="python3" line="1"> print("Blockchain on Node A is currently %s blocks long"%len(chain)) try: print("New Block Received; checking validity...") state = checkBlockValidity(newBlock,chain[-1],state) # Update the state- this will throw an error if the block is invalid! chain.append(newBlock) except: print("Invalid block; ignoring and waiting for the next block...") print("Blockchain on Node A is now %s blocks long"%len(chain)) </syntaxhighlight>Blockchain on Node A is currently 7 blocks long New Block Received; checking validity... Blockchain on Node A is now 8 blocks long === 5 结论与拓展 === 我们已经构建了区块链的所有基本架构,从状态转换规则集到区块创建方法,再到用于验证交易、区块和整条链有效性的机制。我们可以从下载的区块链副本中获取系统状态,验证从网络接收的新区块,并创建我们自己的区块。 我们创建的系统状态实际上是一个分布式账本或数据库——这是许多区块链的核心。我们可以扩展它,使其包含特殊交易类型或完整的智能合约。 我们尚未探讨网络架构、工作量证明或状态证明验证步骤,以及为区块链提供抗攻击安全性的共识机制。我们也尚未讨论公钥密码学、隐私和验证步骤。未来我们将对此进行更深入的探讨!
返回
构建自己的区块链
。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
特殊页面
工具
链入页面
相关更改
页面信息