1. 程式人生 > >區塊鏈技術實現只需50行ruby程式碼!

區塊鏈技術實現只需50行ruby程式碼!

區塊鏈是什麼?作為一個Ruby開發者,理解區塊鏈的最好辦法,就是
親自動手實現一個。只需要50行Ruby程式碼你就能徹底理解區塊鏈技術的核心原理!

區塊鏈 = 區塊組成的連結串列?

class Block

  attr_reader :timestamp
  attr_reader :data
  attr_reader :previous_hash
  attr_reader :hash

  def initialize(data, previous_hash)
    @timestamp     = Time.now
    @data          = data
    @previous_hash
= previous_hash @hash = calc_hash end def self.first( data="Genesis" ) # create genesis (big bang! first) block ## note: uses all zero for previous_hash ("0") Block.new( data, "0000000000000000000000000000000000000000000000000000000000000000" ) end def self.next( previous, data="Transaction Data..." ) Block.new( data, previous.hash ) end
private def calc_hash sha = Digest::SHA256.new sha.update( @timestamp.to_s + @previous_hash + @data ) sha.hexdigest end end # class Block ##### ## let's get started ## build a blockchain a block at a time b0 = Block.first( "Genesis" ) b1 = Block.next( b0, "Transaction Data..."
) b2 = Block.next( b1, "Transaction Data......" ) b3 = Block.next( b2, "More Transaction Data..." ) blockchain = [b0, b1, b2, b3] pp blockchain

執行上面程式:

~$ ruby blockchain.rb

將會輸出類似下面的結果:

[#<Block:0x1eed2a0
  @timestamp     = 1637-09-15 20:52:38,
  @data          = "Genesis",
  @previous_hash = "0000000000000000000000000000000000000000000000000000000000000000",
  @hash          = "edbd4e11e69bc399a9ccd8faaea44fb27410fe8e3023bb9462450a0a9c4caa1b">,
 #<Block:0x1eec9a0
  @timestamp     = 1637-09-15 21:02:38,
  @data          = "Transaction Data...",
  @previous_hash = "edbd4e11e69bc399a9ccd8faaea44fb27410fe8e3023bb9462450a0a9c4caa1b",
  @hash          = "eb8ecbf6d5870763ae246e37539d82e37052cb32f88bb8c59971f9978e437743">,
 #<Block:0x1eec838
  @timestamp     = 1637-09-15 21:12:38,
  @data          = "Transaction Data......",
  @previous_hash = "eb8ecbf6d5870763ae246e37539d82e37052cb32f88bb8c59971f9978e437743",
  @hash          = "be50017ee4bbcb33844b3dc2b7c4e476d46569b5df5762d14ceba9355f0a85f4">,
 #<Block:0x1eec6d0
  @timestamp     = 1637-09-15 21:22:38,
  @data          = "More Transaction Data...",
  @previous_hash = "be50017ee4bbcb33844b3dc2b7c4e476d46569b5df5762d14ceba9355f0a85f4",
  @hash          = "5ee2981606328abfe0c3b1171440f0df746c1e1f8b3b56c351727f7da7ae5d8d">]

你先等等,難道區塊鏈就是連結串列嗎?

當然不是。我們使用連結串列的目的是獲得指向前一個塊的引用:在區塊鏈中,每個塊都必須有一個識別符號,
而這個識別符號還必須依賴於前一個塊的識別符號,這意味著如果你要替換區塊鏈中的一個塊,就必須重算
後面所有塊的識別符號。在上面的實現中,你可以看到我們呼叫calc_hash方法計算塊的識別符號時,需要
傳入前一個塊的簽名,就是這個意思。

那工作量證明演算法呢?

現在讓我們新增工作量證明演算法的實現。在經典的區塊鏈中,你必須通過計算得到00開頭的雜湊作為塊
的識別符號,字首的0越多,計算量就越大,也就越困難。出於簡單考慮,讓我們將難度設定為兩個字首0,
也就是說,2^16 = 256種可能。

def compute_hash_with_proof_of_work( difficulty="00" )
  nonce = 0
  loop do
    hash = calc_hash_with_nonce( nonce )
    if hash.start_with?( difficulty )  
      return [nonce,hash]     ## bingo! proof of work if hash starts with leading zeros (00)
    else
      nonce += 1              ## keep trying (and trying and trying)
    end
  end
end

def calc_hash_with_nonce( nonce=0 )
  sha = Digest::SHA256.new
  sha.update( nonce.to_s + @timestamp.to_s + @previous_hash + @data )
  sha.hexdigest
end

現在我們執行這個增加了POW機制的區塊鏈程式:

~$ ruby blockchain_with_proof_of_work.rb

輸出結果如下:

[#<Block:0x1e204f0
  @timestamp     = 1637-09-20 20:13:38,
  @data          = "Genesis",
  @previous_hash = "0000000000000000000000000000000000000000000000000000000000000000",
  @nonce         = 242,
  @hash          = "00b8e77e27378f9aa0afbcea3a2882bb62f6663771dee053364beb1887e18bcf">,
 #<Block:0x1e56e20
  @timestamp     = 1637-09-20 20:23:38,
  @data          = "Transaction Data...",
  @previous_hash = "00b8e77e27378f9aa0afbcea3a2882bb62f6663771dee053364beb1887e18bcf",
  @nonce         = 46,
  @hash          = "00aae8d2e9387e13c71b33f8cd205d336ac250d2828011f5970062912985a9af">,
 #<Block:0x1e2bd58
  @timestamp     = 1637-09-20 20:33:38,
  @data          = "Transaction Data......",
  @previous_hash = "00aae8d2e9387e13c71b33f8cd205d336ac250d2828011f5970062912985a9af",
  @nonce         = 350,
  @hash          = "00ea45e0f4683c3bec4364f349ee2b6816be0c9fd95cfd5ffcc6ed572c62f190">,
 #<Block:0x1fa8338
  @timestamp     = 1637-09-20 20:43:38,
  @data          = "More Transaction Data...",
  @previous_hash = "00ea45e0f4683c3bec4364f349ee2b6816be0c9fd95cfd5ffcc6ed572c62f190",
  @nonce         = 59,
  @hash          = "00436f0fca677652963e904ce4c624606a255946b921132d5b1f70f7d86c4ab8">]

你看到和前一個版本的差別的嗎?現在所有的hash都是00開頭的,nonce則是獲得這個符合條件
的雜湊時所採用的隨機幸運數字。