尽管有人将区块链视为迟早会出现的问题的解决方案,但毫无疑问,这项创新技术是计算技术的奇迹。那么,区块链到底是什么?区块链是一种数字账本,按时间顺序公开记录比特币或其他加密货币的交易。更通俗地说,它是一个公共数据库,新数据存储在称为块的容器中,并添加到不可变链(因此称为块)。链(blockchain)),之前添加的数据也在链中。对于比特币或其他加密货币,此数据是交易组,但它可以是任何其他类型的数据。区块链技术带来了全新的、完全数字化的货币,如比特币和莱特币,它们不受任何中央机构的管辖。这给那些认为当今银行系统是一个骗局并最终会失败的人带来了自由。区块链还革新了分布式计算的技术形式,例如以太坊(Ethereum)引入了一个有趣的概念:智能合约(smartcontract)。在本文中,我将用不到50行Python2.x代码实现一个简单的区块链,我称之为SnakeCoin。少于50行代码的区块链我们将从定义我们的区块开始。在区块链中,每个块都与时间戳和可选索引一起存储。在SnakeCoin中,我们将两者都存储起来。为了确保整个区块链的完整性,每个区块都会有一个自我识别的哈希值。与比特币一样,每个块的哈希值都是数据的加密哈希值,例如块的索引、时间戳、数据和前一个块的哈希值。这里所说的“数据”可以是任何你想要的数据。将hashlib导入为hasherclass块:def__init__(self,index,timestamp,data,previous_hash):self.index=indexself.timestamp=timestampself.data=dataself.previous_hash=previous_hashself.hash=self.hash_block()defhash_block(self):sha=hasher.sha256()sha.update(str(self.index)+str(self.timestamp)+str(self.data)+str(self.previous_hash))返回sha.hexdigest()太好了,现在我们有了块结构,但是我们需要创建的是一个区块链。我们需要将区块添加到实际的链中。正如我们之前提到的,每个块都需要来自前一个块的信息。但问题是,这个区块链的第一个区块在哪里?好吧,这第一个块,也称为创世块,是一个特殊的块。在许多情况下,它是手动添加的,或通过独特的逻辑添加的。我们将创建一个简单地返回创世块的函数来解决这个问题。该块的索引为0,包含一些任意数据值,其“先前的哈希值”参数也是任意的。importdatetimeasdatedefcreate_genesis_block():#手动构造一个块#索引为零和任意前一个哈希值returnBlock(0,date.datetime.now(),"GenesisBlock","0")现在我们可以创建创世块块,我们需要一个函数来生成区块链中的后续块。该函数将链中的前一个区块作为参数,为要生成的区块创建数据,并返回带有相应数据的新区块。新块是从以前的块中散列出来的,因此每个新块都会增加区块链的完整性。如果我们不这样做,外部参与者很容易“改变过去”并用他们的新链替换我们的链。这个散列链充当加密证明,有助于确保一旦一个块被添加到链中,它就不能被替换或删除。defnext_block(last_block):this_index=last_block.index+1this_timestamp=date.datetime.now()this_data="Hey!I'mblock"+str(this_index)this_hash=last_block.hashreturnBlock(this_index,this_timestamp,this_data,this_hash)这是主体部分。现在我们可以创建自己的区块链了!在这里,这个区块链是一个简单的Python列表。它的第一个元素是我们的创世块,我们将向其添加后续块。因为SnakeCoin是一个非常小的区块链,我们只添加了20个区块。我们通过循环来做到这一点。#创建区块链并添加创世区块链blockchain=[create_genesis_block()]previous_block=blockchain[0]#我们应该向链中添加多少块#在创世之后blocknum_of_blocks_to_add=20#向链中添加块foriinrange(0,num_of_blocks_to_add):block_to_add=next_block(previous_block)blockchain.append(block_to_add)previous_block=block_to_add#告诉大家吧!print"Block#{}hasbeenaddedtotheblockchain!".format(block_to_add.index)print"Hash:{}\n".format(block_to_add.hash)让我们看看我们的结果:别担心,它会添加直到第20个区块。很好,我们的区块链可以正常工作。如果你想在控制台中查看更多信息,你可以编辑它的完整源代码并输出每个块的时间戳或数据。这就是SnakeCoin所做的。SnakeCoin要达到今天生产级区块链的高度,我们需要添加更多的功能,比如一个服务器层来跟踪多台机器上的链变化,通过工作量证明限制给区块链的交易数量算法(战俘)。在给定时间段内可以添加的块数。如果您需要更多技术细节,可以在此处查看原始比特币白皮书。把这个小区块链做大一点这个小区块链非常简单,自然也比较容易完成。但它的简单性也有一些缺点。首先,SnakeCoin只能在单机上运行,??因此它离分布式很远,更谈不上去中心化。其次,在主机上创建Python对象并添加到列表中时,块就会被快速添加到区块链中。在我们简单的区块链中,这不是问题,但如果我们希望SnakeCoin成为一种实际的加密货币,我们需要控制在给定时间可以创建的块(和硬币)的数量。今后,蛇币中的“数据”就是交易数据,每个区块的“数据”字段就是一些交易信息的列表。接下来,让我们定义一个“事务”。每笔“交易”都是一个JSON对象,记录了币的发送方、接收方以及转出的SnakeCoin金额。注意:交易信息为JSON格式,原因我稍后会解释。{"from":"71238uqirbfh894-random-public-key-a-alkjdflakjfewn204ij","to":"93j4ivnqiopvh43-random-public-key-b-qjrgvnoeirbnferinfo","amount":3}现在我们知道交易信息了它看起来像这样,我们需要一种方法将它添加到我们区块链网络中的计算机(称为节点)。为此,我们将创建一个简单的HTTP服务器,以便每个用户都可以让我们的节点知道发生了新事务。节点可以接受POST请求,请求数据为上述交易信息。这就是交易信息采用JSON格式的原因:我们需要将它们在请求消息中传递给服务器。$pipinstallflask#首先安装web服务器框架fromflaskimportFlaskfromflaskimportrequestnode=Flask(__name__)#将这个节点拥有的事务存储在一个列表中this_nodes_transactions=[]@node.route('/txion',methods=['POST'])deftransaction():ifrequest.method=='POST':#在每个新的POST请求中,#我们提取交易数据new_txion=request.get_json()#然后我们将交易添加到我们的listthis_nodes_transactions.append(new_txion)#因为事务已成功提交,我们将其记录到我们的控制台print"Newtransaction"print"FROM:{}"。格式(new_txion['from'])打印“TO:{}”。format(new_txion['to'])print"AMOUNT:{}\n".format(new_txion['amount'])#然后我们让客户知道它成功了return"Transactionsubmissionsuccessful\n"node.run()太棒了!现在我们有办法记录用户相互发送SnakeCoins的情况。这就是人们将区块链称为公共分布式账本的原因:所有交易信息都存储起来供所有人查看,并存储在网络的每个节点上。然而,有一个问题:人们从哪里得到蛇币?目前还没有办法得到它,没有蛇币这样的东西,因为我们还没有创建和分发任何硬币。要创建一枚新硬币,需要“挖掘”一个新的SnakeCoin区块。当他们成功挖掘出一个新区块时,一个新的SnakeCoin将被创建并奖励给挖掘该区块的人(矿工)。一旦挖矿矿工将SnakeCoin发送给其他人,该币就会进入流通。我们不想让挖掘新的SnakeCoin区块变得太容易,因为那样会导致SnakeCoins太多,它们的价值就会变低;同样,我们也不想让它变得太难,因为如果没有足够的硬币供每个人使用,它们对我们来说太贵了。为了控制挖掘新SnakeCoin区块的难度,我们将实施工作量证明(PoW)算法。工作量证明基本上是一种难以生成特定项目但易于验证(其正确性)的算法。该项目被称为“证明”,听起来像是证明计算机已经执行了特定数量的工作。在SnakeCoin中,我们创建了一个简单的PoW算法。要创建一个新块,矿工的计算机需要递增一个数字。当这个数字能被9(“SnakeCoin”这个词的字母数)整除时,这就是最新区块的证明编号,一个新的SnakeCoin区块,矿工将得到一个新的SnakeCoin。#...区块链#...块类定义miner_address="q3nf394hjg-random-miner-address-34nf3i4nflkn3oi"defproof_of_work(last_proof):#创建一个我们将用来查找的变量#我们的下一个工作量证明incrementor=last_proof+1#继续递增增量器,直到它等于一个可以被9整除的数字#以及链中前一个区块的工作证明whilenot(incrementor%9==0andincrementor%last_proof==0):incrementor+=1#一旦找到那个数字,#我们可以将它作为我们工作的证明返回它returnincrementor@node.route('/mine',methods=['GET'])defmine():#获取最后一个工作量证明last_block=blockchain[len(blockchain)-1]last_proof=last_block.data['proof-of-work']#找到#当前正在开采的区块的工作量证明#注意:程序将挂在这里直到#找到一个新的工作量证明proof=proof_of_work(last_proof)#一旦我们找到一个有效的pro的工作,#我们知道我们可以开采一个区块,所以我们通过添加交易来奖励矿工this_nodes_transactions.append({"from":"network","to":miner_address,"amount":1})#现在我们可以收集创建新块所需的数据new_block_data={"proof-of-work":proof,"transactions":list(this_nodes_transactions)}new_block_index=last_block.index+1new_block_timestamp=this_timestamp=date.datetime.now()last_block_hash=last_block.hash#清空交易列表this_nodes_transactions[:]=[]#现在创建#新块!mined_block=Block(new_block_index,new_block_timestamp,new_block_data,last_block_hash)blockchain.append(mined_block)#让客户端知道我们挖了一个块returnjson.dumps({"index":new_block_index,"timestamp":str(new_block_timestamp),"data“:新的_block_data,"hash":last_block_hash})+"\n"现在,我们可以控制在特定时间段内开采的区块数量,我们将新币提供给网络中的人们,让他们互相发送,但正如我们所说,我们只是在一台电脑上完成的。如果区块链是去中心化的,我们如何保证每个节点都有相同的链?为此,我们将让每个节点广播其(保存的)链版本,并允许它们接受其他节点的链。然后,每个节点将验证其他节点的链,从而使网络中的每个节点对最终链达成共识。这称为共识算法。我们的共识算法很简单:如果一个节点的链与其他节点的链不同(例如冲突),则保留最长的链并删除较短的链。如果我们网络上的链没有冲突,那么我们可以继续。@node.route('/blocks',methods=['GET'])defget_blocks():chain_to_send=blockchain#将我们的块转换成字典#这样我们可以稍后将它们作为json对象发送forblockinchain_to_send:block_index=str(block.index)block_timestamp=str(block.timestamp)block_data=str(block.data)block_hash=block.hashblock={“index”:block_index,“timestamp”:block_timestamp,“data”:block_data,“hash”:block_hash}#将我们的链发送给任何请求它的人chain_to_send=json.dumps(chain_to_send)returnchain_to_senddeffind_new_chains():#获取每个其他节点的区块链other_chains=[]fornode_urlinpeer_nodes:#使用GET获取他们的链requestblock=requests.get(node_url+"/blocks").content#将JSON对象转换为Python字典block=json.loads(block)#添加到我们的列表other_chains.append(block)returnother_chainsdefconsensus():#从其他节点获取区块other_chains=find_new_chains()#如果我们的链不是最长的,#然后我们存储最长的链longest_chain=blockchainforchaininother_chains:iflen(longest_chain)
