麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 專題 > 區塊鏈 > 正文

用Python實現一個區塊鏈

2020-02-25 19:29:02
字體:
來源:轉載
供稿:網友

  相信你和我一樣對數字貨幣的崛起感到新奇,并且想知道其背后的技術——區塊鏈是怎樣實現的。

  但是理解區塊鏈并非易事,至少對于我來說是如此。晦澀難懂的視頻、漏洞百出的教程以及示例的匱乏令我倍受挫折。

  我喜歡在實踐中學習,通過寫代碼來學習技術會掌握得更牢固。如果你也這樣做,那么讀完本文,你將獲得一個可用的區塊鏈以及對區塊鏈的深刻理解。

  開始之前...

  首先你需要知道區塊鏈是由被稱為區塊的記錄構成的不可變的、有序的鏈式結構,這些記錄可以是交易、文件或任何你想要的數據,最重要的是它們是通過 Hash 連接起來的。

  如果你不了解 Hash,這里有個例子

  其次,你需要安裝 Python3.6+,Flask,Request

  pip installFlask==0.12.2requests==2.18.4

  同時你還需要一個 HTTP 客戶端,比如 Postman,cURL 或任何其它客戶端。

  最終的源代碼在這里:

  第一步: 打造一個 Blockchain

  新建一個文件 blockchain.py,本文所有的代碼都寫在這一個文件中。首先創建一個 Blockchain 類,在構造函數中我們創建了兩個列表,一個用于儲存區塊鏈,一個用于儲存交易。

  classBlockchain(object):

  def__init__(self):

  self.chain=[]

  self.current_transactions=[]

  defnew_block(self):

  # Creates a new Block and adds it to the chain

  pass

  defnew_transaction(self):

  # Adds a new transaction to the list of transactions

  pass

  @staticmethod

  defhash(block):

  # Hashes a Block

  pass

  @property

  deflast_block(self):

  # Returns the last Block in the chain

  pass

  一個區塊有五個基本屬性:index,timestamp(in Unix time),transaction 列表,工作量證明(稍后解釋)以及前一個區塊的 Hash 值。

  block={

  'index':1,

  'timestamp':1506057125.900785,

  'transactions':[

  {

  'sender':"8527147fe1f5426f9dd545de4b27ee00",

  'recipient':"a77f5cdfa2934df3954a5c7c7da5df1f",

  'amount':5,

  }

  ],

  'proof':324984774000,

  'previous_hash':"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

  }

  到這里,區塊鏈的概念應該比較清楚了:每個新的區塊都會包含上一個區塊的 Hash 值。這一點非常關鍵,它是區塊鏈不可變性的根本保障。如果攻擊者破壞了前面的某個區塊,那么后面所有區塊的 Hash 都會變得不正確。不理解?慢慢消化~

  我們需要一個向區塊添加交易的方法:

  classBlockchain(object):

  ...

  defnew_transaction(self,sender,recipient,amount):

  """

  Creates a new transaction to go into the next mined Block

  :param sender: Address of the Sender

  :param recipient: Address of the Recipient

  :param amount: Amount

  :return: The index of the Block that will hold this transaction

  """

  self.current_transactions.append({

  'sender':sender,

  'recipient':recipient,

  'amount':amount,

  })

  returnself.last_block['index']+1

  new_transaction() 方法向列表中添加一個交易記錄,并返回該記錄將被添加到的區塊——下一個待挖掘的區塊——的索引,稍后在用戶提交交易時會有用。

  當 Blockchain 實例化后,我們需要創建一個初始的區塊(創世塊),并且給它預設一個工作量證明。

  除了添加創世塊的代碼,我們還需要補充 newblock(), newtransaction() 和 hash() 方法:

  importhashlib

  importjson

  fromtimeimporttime

  classBlockchain(object):

  def__init__(self):

  self.current_transactions=[]

  self.chain=[]

  # Create the genesis block

  self.new_block(previous_hash=1,proof=100)

  defnew_block(self,proof,previous_hash=None):

  block={

  'index':len(self.chain)+1,

  'timestamp':time(),

  'transactions':self.current_transactions,

  'proof':proof,

  'previous_hash':previous_hashorself.hash(self.chain[-1]),

  }

  # Reset the current list of transactions

  self.current_transactions=[]

  self.chain.append(block)

  returnblock

  defnew_transaction(self,sender,recipient,amount):

  self.current_transactions.append({

  'sender':sender,

  'recipient':recipient,

  'amount':amount,

  })

  returnself.last_block['index']+1

  @property

  deflast_block(self):

  returnself.chain[-1]

  @staticmethod

  defhash(block):

  block_string=json.dumps(block,sort_keys=True).encode()

  returnhashlib.sha256(block_string).hexdigest()

  上面的代碼應該很直觀,我們基本上有了區塊鏈的雛形。但此時你肯定很想知道一個區塊究竟是怎樣被創建或挖掘出來的。

  新的區塊來自工作量證明(PoW)算法。PoW 的目標是計算出一個符合特定條件的數字,這個數字對于所有人而言必須在計算上非常困難,但易于驗證。這就是工作量證明的核心思想。

  舉個例子:

  假設一個整數 x 乘以另一個整數 y 的積的 Hash 值必須以 0 結尾,即 hash(x * y) = ac23dc...0。設 x = 5,求 y?

  fromhashlibimportsha256

  x=5

  y=0# We don't know what y should be yet...

  whilesha256(f'{x*y}'.encode()).hexdigest()[-1]!="0":

  y+=1

  print(f'The solution is y = {y}')

  結果是 y = 21 // hash(5 * 21) = 1253e9373e...5e3600155e860

  在比特幣中,工作量證明算法被稱為 Hashcash,它和上面的問題很相似,只不過計算難度非常大。這就是礦工們為了爭奪創建區塊的權利而爭相計算的問題。通常,計算難度與目標字符串需要滿足的特定字符的數量成正比,礦工算出結果后,就會獲得一定數量的比特幣獎勵(通過交易)。

  網絡要驗證結果,當然非常容易。

  讓我們來實現一個 PoW 算法,和上面的例子非常相似,規則是:尋找一個數 p,使得它與前一個區塊的 proof 拼接成的字符串的 Hash 值以 4 個零開頭。

  importhashlib

  importjson

  fromtimeimporttime

  fromuuidimportuuid4

  classBlockchain(object):

  ...

  defproof_of_work(self,last_proof):

  proof=0

  whileself.valid_proof(last_proof,proof)isFalse:

  proof+=1

  returnproof

  @staticmethod

  defvalid_proof(last_proof,proof):

  guess=f'{last_proof}{proof}'.encode()

  guess_hash=hashlib.sha256(guess).hexdigest()

  returnguess_hash[:4]=="0000"

  衡量算法復雜度的辦法是修改零的個數。4 個零足夠用于演示了,你會發現哪怕多一個零都會大大增加計算出結果所需的時間。

  我們的 Blockchain 基本已經完成了,接下來我們將使用 HTTP requests 來與之交互。

  第二步:作為 API 的 Blockchain

  我們將使用 Flask 框架,它十分輕量并且很容易將網絡請求映射到 Python 函數。

  我們將創建三個接口:

  /transactions/new創建一個交易并添加到區塊

  /mine告訴服務器去挖掘新的區塊

  /chain返回整個區塊鏈

  我們的服務器將扮演區塊鏈網絡中的一個節點。我們先添加一些常規代碼:

  importhashlib

  importjson

  fromtextwrapimportdedent

  fromtimeimporttime

  fromuuidimportuuid4

  fromflaskimportFlask,jsonify,request

  classBlockchain(object):

  ...

  # Instantiate our Node

  app=Flask(__name__)

  # Generate a globally unique address for this node

  node_identifier=str(uuid4()).replace('-','')

  # Instantiate the Blockchain

  blockchain=Blockchain()

  @app.route('/mine',methods=['GET'])

  defmine():

  return"We'll mine a new Block"

  @app.route('/transactions/new',methods=['POST'])

  defnew_transaction():

  return"We'll add a new transaction"

  @app.route('/chain',methods=['GET'])

  deffull_chain():

  response={

  'chain':blockchain.chain,

  'length':len(blockchain.chain),

  }

  returnjsonify(response),200

  if__name__=='__main__':

  app.run(host='127.0.0.1',port=5000)

  這是用戶發起交易時發送到服務器的請求:

  {

  "sender":"my address",

  "recipient":"someone else's address",

  "amount":5

  }

  我們已經有了向區塊添加交易的方法,因此剩下的部分就很簡單了:

  @app.route('/transactions/new',methods=['POST'])

  defnew_transaction():

  values=request.get_json()

  # Check that the required fields are in the POST'ed data

  required=['sender','recipient','amount']

  ifnotall(kinvaluesforkinrequired):

  return'Missing values',400

  # Create a new Transaction

  index=blockchain.new_transaction(values['sender'],values['recipient'],values['amount'])

  response={'message':f'Transaction will be added to Block {index}'}

  returnjsonify(response),201

  挖掘端正是奇跡發生的地方,它只做三件事:計算 PoW;通過新增一個交易授予礦工一定數量的比特幣;構造新的區塊并將其添加到區塊鏈中。

  @app.route('/mine',methods=['GET'])

  defmine():

  # We run the proof of work algorithm to get the next proof...

  last_block=blockchain.last_block

  last_proof=last_block['proof']

  proof=blockchain.proof_of_work(last_proof)

  # We must receive a reward for finding the proof.

  # The sender is "0" to signify that this node has mined a new coin.

  blockchain.new_transaction(

  sender="0",

  recipient=node_identifier,

  amount=1,

  )

  # Forge the new Block by adding it to the chain

  block=blockchain.new_block(proof)

  response={

  'message':"New Block Forged",

  'index':block['index'],

  'transactions':block['transactions'],

  'proof':block['proof'],

  'previous_hash':block['previous_hash'],

  }

  returnjsonify(response),200

  需注意交易的接收者是我們自己的服務器節點,目前我們做的大部分事情都只是圍繞 Blockchain 類進行交互。到此,我們的區塊鏈就算完成了。

  第三步:交互演示

  使用 Postman 演示,略。

  第四步:一致性

  這真的很棒,我們已經有了一個基本的區塊鏈可以添加交易和挖礦。但是,整個區塊鏈系統必須是分布式的。既然是分布式的,那么我們究竟拿什么保證所有節點運行在同一條鏈上呢?這就是一致性問題,我們要想在網絡中添加新的節點,就必須實現保證一致性的算法。

  在實現一致性算法之前,我們需要找到一種方式讓一個節點知道它相鄰的節點。每個節點都需要保存一份包含網絡中其它節點的記錄。讓我們新增幾個接口:

  1./nodes/register接收以URL的形式表示的新節點的列表

  2./nodes/resolve用于執行一致性算法,用于解決任何沖突,確保節點擁有正確的鏈

  ...

  fromurllib.parseimporturlparse

  ...

  classBlockchain(object):

  def__init__(self):

  ...

  self.nodes=set()

  ...

  defregister_node(self,address):

  parsed_url=urlparse(address)

  self.nodes.add(parsed_url.netloc)

  注意到我們用 set 來儲存節點,這是一種避免重復添加節點的簡便方法。

  前面提到的沖突是指不同的節點擁有的鏈存在差異,要解決這個問題,我們規定最長的合規的鏈就是最有效的鏈,換句話說,只有最長且合規的鏈才是實際存在的鏈。

  讓我們再添加兩個方法,一個用于添加相鄰節點,另一個用于解決沖突。

  ...

  importrequests

  classBlockchain(object)

  ...

  defvalid_chain(self,chain):

  last_block=chain[0]

  current_index=1

  whilecurrent_index(chain):

  block=chain[current_index]

  print(f'{last_block}')

  print(f'{block}')

  print("n-----------n")

  # Check that the hash of the block is correct

  ifblock['previous_hash']!=self.hash(last_block):

  returnFalse

  # Check that the Proof of Work is correct

  ifnotself.valid_proof(last_block['proof'],block['proof']):

  returnFalse

  last_block=block

  current_index+=1

  returnTrue

  defresolve_conflicts(self):

  neighbours=self.nodes

  new_chain=None

  # We're only looking for chains longer than ours

  max_length=len(self.chain)

  # Grab and verify the chains from all the nodes in our network

  fornodeinneighbours:

  response=requests.get(f'http://{node}/chain')

  ifresponse.status_code==200:

  length=response.json()['length']

  chain=response.json()['chain']

  # Check if the length is longer and the chain is valid

  iflength>max_lengthandself.valid_chain(chain):

  max_length=length

  new_chain=chain

  # Replace our chain if we discovered a new, valid chain longer than ours

  ifnew_chain:

  self.chain=new_chain

  returnTrue

  returnFalse

  現在你可以新開一臺機器,或者在本機上開啟不同的網絡接口來模擬多節點的網絡,或者邀請一些朋友一起來測試你的區塊鏈。

  我希望本文能激勵你創造更多新東西。我之所以對數字貨幣入迷,是因為我相信區塊鏈會很快改變我們看待事物的方式,包括經濟、政府、檔案管理等。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: lutube成人福利在线观看 | 国产一级毛片国语版 | 日韩视频―中文字幕 | 国产精品久久国产精麻豆96堂 | 欧美一级淫片免费视频黄 | 55夜色66夜色国产精品视频 | 一级成人欧美一区在线观看 | 久久精品视频免费观看 | 欧美韩国日本在线 | 国产88久久久国产精品免费二区 | 亚州精品国产 | 国产乱淫av片免费 | 国产精品一区二区视频 | 欧美性成人 | 精品爱爱| 亚洲情av | 在线播放的av网站 | 免费看性xxx高清视频自由 | 中文字幕在线观看成人 | 成人性生活视频在线播放 | 亚洲第一激情 | 美女在线视频一区二区 | 国产女同玩人妖 | 一级做受毛片免费大片 | 亚洲精品一区二区三区免 | 一级做a在线观看 | 91精品国产九九九久久久亚洲 | 91九色免费视频 | 国产1区2区3区中文字幕 | 欧美成人精品一区二区 | 羞羞视频在线免费 | 久久精品中文字幕一区二区 | 成人在线免费小视频 | 免费日本一区二区 | 国产超碰人人做人人爱 | 天堂在线中文资源 | 一级片九九 | 日本中文字幕电影在线观看 | 国产精品视频专区 | 午夜视频亚洲 | 美女黄网站免费观看 |