部分引用自:SatwikKansal用Python从头开发一个区块链应用比特币这两天飙升至9000美元。币块减半的因素在里面。不过这些都不是今天文章的重点。今天我们将重点介绍比特币交易(账户间转移比特币)的原理——区块链。并用它来构建一个简单的去中心化食品安全溯源区块链。区块链是一种存储数字数据的方式,可以是任何东西。对于比特币来说,就是账户之间转移比特币的交易。我们还可以将其应用到食品安全领域,就是节省食品生产过程中每一步的时间、原材料、生产者等。用区块链来记录这些过程是非常有优势的,因为区块链可以有以下特点:1.历史记录不可修改(本文重点)2.数据去中心化存储3.没有单点故障扫描文章下方二维码关注Python实战宝典公众号,回复食品安全溯源获取完整源码。1.将数据存储在block中我们将使用json来保存我们想要的数据,下面是一个例子:{"timestamp":"1572185927665","source":"香肠加工","recorder":"肖战“}2。使区块不可更改为了保证历史记录不可修改,一旦修改了区块的数据我们就可以检测到任何篡改,所以我们需要使用哈希函数SHA256,它可以从任何数据中获取中心创建数字指纹以保证数据的唯一性。下面是一个例子:fromhashlibimportsha256data="TEST".encode("utf-8")print(sha256(data).hexdigest())然后我们把哈希的结果保存到块的一个字段中,它就像它包含的数据的数字指纹一样:fromhashlibimportsha256importjsonclassBlock:defcompute_hash(self):"""Computethehashoftheblock"""block_string=json.dumps(self.__dict__,sort_keys=True)returnsha256(block_string.encode()).hexdigest()3.链接块我们已经设置了块,但是区块链应该是块的集合,我们可以将所有的块存储在一个列表中,但这远远不够,如果有人故意替换一个块怎么办?我们需要一些方法来确保对过去区块的任何更改都会使整个链无效。我们将通过哈希链接块,即在当前块中包含前一个块的哈希。所以如果当前区块的内容发生变化,那么该区块的哈希值也会发生变化,导致下一个区块与前一个区块的哈希字段(previous_hash)不匹配。每个块都根据previous_hash字段链接到前一个块,但是第一个块(创世块)呢?在大多数情况下,我们会手动分配它。添加索引、时间戳、数据段和previous_hash来块类初始化:fromhashlibimportsha256importjsonclassBlock:def__init__(self,index,data,timestamp,previous_hash):self.index=indexself.data=dataself.timestamp=timestampself.previous_hash=previous_hashdefcompute_hash(self):"""Computetheblockhash"""block_string=json.dumps(self.__dict__,sort_keys=True)returnsha256(block_string.encode()).hexdigest()这是ourblockchainclass:classBlockchain:def__init__(self):self.unconfirmed_data=[]#还没有进入区块链的数据self.chain=[]self.create_genesis_block()defcreate_genesis_block(self):"""一个函数生成一个创世块并将其附加到链上。该块的索引为0,previous_hash为0,并且是一个有效的哈希。"""genesis_block=Block(0,[],time.time(),"0")genesis_block.hash=genesis_block.compute_hash()self.chain.append(genesis_block)@propertydeflast_block(self):返回自我。chain[-1]4.工作量证明算法实际上是这样做的,这远远不够。因为我们可以很容易地通过改变前一个块来计算出所有后续块的哈希值,并创建一个不同的有效区块链。以防止为此,我们必须让计算哈希的任务变得困难和随机。我们将引入一个约束和一个称为随机数的新字段。这个约束是区块哈希头中零(leadingzeros)的个数,随机数会不断地改变直到我们得到满足约束的哈希值。前导零的数量决定了工作量证明算法的难度。看看下面的比特币框图是的,比特币的难度增加是通过增加数量来实现的前导零。假设我们的难度是2,工作量证明算法的代码如下:classBlockchain:#前面的代码略#难度difficulty=2defproof_of_work(self,block):"""函数尝试不同的nonces来得到一个块哈希这满足了我们的困难。"""block.nonce=0computed_hash=block.compute_hash()whilenotcomputed_hash.startswith('0'*Blockchain.difficulty):block.nonce+=1computed_hash=block.compute_hash()returncomputed_hash这有一个优点:随机数只能通过一个剧烈的循环来确定,??这也是现在挖矿行业如此火爆的原因。5.向链中添加区块要向链中添加区块,我们首先验证工作量证明是否正确,以及要添加的区块的previous_hash字段是否指向链中最新区块的哈希值。classBlockchain:#前面的代码略defis_valid_proof(self,block,block_hash):"""验证工作量证明,并确保previous_hash正确"""return(block_hash.startswith('0'*Blockchain.difficulty)andblock_hash==block.compute_hash())defadd_block(self,block,proof):"""Chainblocksaftersuccessfulverification"""previous_hash=self.last_block.hashifprevious_hash!=block.previous_hash:returnFalseifnotself.is_valid_proof(block,proof):返回Falseblock.hash=proofself.chain.append(block)返回True6。挖矿数据会存储在unconfirmed_data中,将unconfirmed_data中的数据放入区块并计算工作量,证明的过程称为挖矿。一旦我们找到一个满足约束条件的随机数,我们就可以说我们已经挖出了一个区块,并且这个区块被放入了区块链。在比特币中,矿工可以获得一些加密货币作为计算工作量证明的计算能力的奖励。下面是我们的挖矿函数:unconfirmed_data.append(data)defmine(self):"""此函数充当一个接口,用于将待处理数据添加到块并在将它们添加到区块链之前计算工作量证明。"""如果不是self。unconfirmed_data:returnFalselast_block=self.last_blocknew_block=Block(index=last_block.index+1,data=self.unconfirmed_data,timestamp=time.time(),previous_hash=last_block.hash)proof=self.proof_of_work(new_block)self.add_block(new_block,proof)self.unconfirmed_data=[]returnnew_block.indextest至此,链条基本搭建完成,我们来试试效果。尝试向其中添加一个块:defnew_data(data):#你可以在此处传入字典数据或json数据required_fields=["source","recorder"]forfieldinrequired_fields:ifnotdata.get(field):return"Invlaiddata"data["timestamp"]=time.time()bc.add_new_data(data)return"Success"bc=Blockchain()a=new_data({"source":"香肠加工","recorder":"肖战"})print(a)添加成功:F:push20191027>pythonblock.pySuccess现在数据在unconfirmed_data中,我们需要挖矿才能成功添加到区块链中:defnew_data(data):#Eitherdictionary这里可以传入data或者json数据。required_fields=["source","recorder"]forfieldinrequired_fields:ifnotdata.get(field):return"Invlaiddata"数据["timestamp"]=time.time()bc.add_new_data(data)return"成功”defget_chain(blockchain):chain_data=[]forblockinblockchain.chain:chain_data.append(block.__dict__)returnjson.dumps({"length":len(chain_data),"chain":chain_data})def我的_unconfirmed_transactions(blockchain):result=blockchain.mine()ifnotresult:print("Nodataneedtomine")打印("Block#{}ismined.".format(result))bc=Blockchain()a=new_data({"source":"SausageProcessing","recorder":"XiaoZhan"})print(a)mine_unconfirmed_transactions(bc)output:F:push20191027>pythonblock.pySuccessBlock#1被挖出。我们现在看一下区块链上有没有两个区块(一个创世区块和一个我们添加的新区块)显示数据:defget_chain(blockchain):chain_data=[]forblockinblockchain.chain:chain_data.append(block.__dict__)returnjson.dumps({"length":len(chain_data),"chain":chain_data})print(get_chain(bc))结果:F:push20191027>pythonblock.pySuccessBlock#1被开采。{“长度”:2,“链”:[{“索引”:0,“数据”:[],“时间戳”:1572187230.2847784,“previous_hash”:“0”,“哈希”:“f30161fc8ffa278f26713a73780b939fe9734d9d459fe4307e729”26d9,索引{:1,“数据”:[{“来源”:“u9999u80a0u52a0u5de5”,“记录器”:“u5c0fu8a79”,“时间戳”:1572187230.2847784}],“蒂姆estamp":1572187230.2847784,"previous_hash":"f30161fc8ffa278f26713a73780b939fe9734d9d459fe4307e72926d9eb9c3aa","nonce":0,"hash":"0026b22937fdcb24978814dd26cdf64a6210966c26914e66b73ca68805f1cd5a"}]}非常nice,这样我们就成功新建了一个非常简单的食品安全溯源区块链,当然上线还有很长的路要走(比如去中心化和建立共识),但万事开头难,解决了第一部分,以后就不会再有问题了,扫描文章下方二维码即可关注Python实战宝典公众号,回复食品安全溯源即可获取完整源码,本文到此结束,如果喜欢今天的Python教程,请继续关注Python实战宝典,如果对对你有帮助,请在下方点赞/观看有问题可以在下方留言区留言,我们会耐心解答!Python实战宝典(pythondict.com)不只是一个合集,欢迎来到注意on公众号:Python实战宝典原文来自:Python构建简单的食品安全溯源区块链
