歡迎光臨
我們一直在努力

用Ruby實現一個最簡的區塊鏈


   一個 Ruby 實現的 Blockchain 導讀


Blockchain  是一種革命性的技術, 有些抽象, 比較複雜. 自從比特幣誕生以來, 有很多技術的科普文章, 甚至是製精良的動畫, 來解釋其中的原理. 其中不乏精品之作.

在區塊鏈的世界, 閱讀理論的作用是有限的. 離開實踐, 力有不逮, 心有餘而力不逮, 是很常見的. 從白皮書到代碼實現是一個飛躍, 需要一些耐心和技術儲備.

積累  Blockchain  的設計細節, 掌握某種編程語言是需要時間的, 適合的學習材料會縮短這個過程. 並且讓你妥帖的撫摸區塊的皮膚, 感受其鍊式形體. 

另一方面, 一旦製作出一個完整的   Blockchain  的 Demo, 這項技術瞬間與你的靈魂結合, 留下虔誠的烙印和神聖的宗教代碼.

2017年末, 知名的  Blockchainist , 利他主義猛士 Haseeb Qureshi 先生, 發布了一個  Blockchain  Demo 視頻及代碼, 這是一場兩個小時的儀式, 是賽博朋克洗禮的聖水.

對  Blockchainist  而言, 若未曾實現一個小小的 Demo, 猶如應和了一句古話: 為人不識陳近南,就稱英雄也枉然。

學習這個小項目, 猶如在你修煉區塊神功時, 將 Haseeb 的剛猛內力傳入你體內, 雖可以加速修煉進度, 但也存在水土不服, 心情煩躁, 走火入魔的風險. 

當你吸入, 消化洋人內力時, 需要本尊這粒藥引子, 去腥除騷, 護體保平安.

下面逐層介紹神功的實現目標以及必備知識.


神功第一層  
錢坤大挪移,
謝遜度假夏威夷

這一層實現查賬轉賬功能, 轉賬功能是根據賬戶餘額, 進行加減計算.

此類功能用  HTTP  協議的  GET  和  POST  實現最適合,  GET  用來獲取服務端數據,  POST  用來更改服務端數據.

這裡不需要  HTML  來呈現 UI, 使用 Ruby Web 框架  Sinatra  來組織  URL  和相關的  method , 在命令行終端可以看到轉賬信息.

客戶端的  method  和服務端的  url  都非常簡潔

客戶端: client.rb

  def  create_user(name) … end   def  get_balance(user)  … end   def  transfer(from, to, amount) ... end 

服務端: haseebcoin.rb

 get “/balance” ... end  post “/users” ... end  post “/transfers” ... end 

本層必要知識:  ruby HTTP   GET   POST Sinatra


神功第二層  
白玉堂大破銅網陣

姦王私建沖霄樓, 銅網陣, 裡面遍布是消息埋伏, 探測環境變化, 傳遞信息, 觸動奪命機關.

中描述了一種致命的物聯網, 區塊鏈中也有類似的結構,  Gossip Protocols  八卦, 不是乾, 坤, 坎, 離… 是八卦新聞的意思, 是去中心化網絡.

我們建立一個能夠交換電影名稱的  Gossip  網絡.

client.rb 實現了向某端口送消息

def  self .gossip(port, state) 
 ...  

 
Faraday .post( " #{ URL } : #{port} /gossip" , state: state).body

 ...


end

gossip.rb  接受兩個參數, 源端口和目的端口, 源端口在某個端口說話, 比如端口  1111 2222 .

在實際的去中心網絡中, 這倆端口代表兩個網絡節點, 在本機上不同端口說話, 模擬網絡中的不同的節點.

每個節點
每  3  秒, 說出最愛電影名稱

every( 3 .seconds) do  …

   gossip_response = Client .gossip(port, JSON .dump( STATE ))

   update_state( JSON .load(gossip_response))

   ... 

end

每 8 秒, 改變最愛電影.

every( 8 .seconds) do  …

   update_state( PORT => [ @favorite_movie , @version_number ])

   ... 

end

服務端接收並處理數據

post '/gossip'  do  …

   update_state( JSON .load(their_state))

   … 

end

在一個四人網絡中:

  1. 初始節點運行 gossip.rb 1111 , 第一節點在 1111 端口說出最愛電影

  2. 運行  gossip.rb 2222 1111 , 第二節點在 2222 端口向第一節點 (1111 端口) 說出最愛電影

  3. 運行  gossip.rb 3333 2222 , 第三節點在 3333 端口向第二節點 (2222 端口) 說出最愛電影

  4. 運行  gossip.rb 4444 3333 , 第四節點在 4444 端口向第三節點 (3333 端口) 說出最愛電影

運行一段時間後, 最終, 四個節點都有對方的信息, 而且信息在不停的變化. 這就是一個簡單的  Gossip  網絡.


神功第三層  
倚天屠龍藏玄機, 
武穆遺書加解密

完顏洪烈道:“岳飛無法可施,只得把那部兵書貼身藏了,寫了四首甚麼《菩薩蠻》、《醜奴兒》、《賀聖朝》、《齊天樂》的歪詞。

這四首詞格律不對,平仄不葉,句子顛三倒四,不知所云。 ”

“哪知其中竟是藏著一個極大的啞謎。

小王苦苦思索,終於解明了,原來這四首歪詞須得每隔三字的串讀,先倒後順,反复連貫,便即明明白白。 ”

頂級加密算法是區塊鏈的基石.

這一層使用非對稱加密技術, 實現區塊鏈賬戶.

RSA  算法能夠生成公鑰, 私鑰, 並實現非對稱加密功能.

def  generate_key_pair … end 
def  sign(plaintext, raw_private_key) ... end 

得益於  Ruby  語言的  openssl module , 我們可以很輕鬆的實現非對稱加密和簽名驗證等功能.
在區塊鏈中, 公鑰是用戶名, 私鑰是密碼, 一對密鑰, 就是一個區塊鏈賬戶.

解密 ciphertext:

def  plaintext(ciphertext, raw_public_key) … end 

驗證 ciphertext 是不是 message:

def  valid_signature?(message, ciphertext, public_key) … end 

本層必要知識: 非對稱加密算法


神功第四層  
老君爐裡賴一年, 
釀製區塊出金丹

這一層實現了工作證明, 產生了區塊鏈中的區塊, 是費時費力的過程.
Hash Function 的特點是不可逆和無衝突, 計算過程很簡單, 將  input  經過哈希運算, 得到  result ,
input  是轉賬, 錢, 花錢的人, 收錢的人等等信息

哈希運算有很多種算法, 這裡使用  SHA256  算法:

def  hash(message) … end 

同樣的信息, 做同樣的哈希運算, 會得到不同的 result, 我們不停的做運算, 直到得到的 result 符合某些特性, 比如 result 前幾位都是 0.

驗證運算結果是不是以幾個 0 開始:

def  is_valid_nonce?(nonce, message)

   hash(message + nonce).start_with?( "0" * NUM_ZEROES ) 

end

符合以上條件運算執行起來不是那麼容易, 需要耗費大量時間, 整個過程被稱為挖礦:

def  find_nonce(message)

   …   

 until is_valid_nonce?(nonce, message)    ...

end

input  中會包含上一次哈希運算的結果, 所以每次哈希運算都收到了上一次運算的影響, 換句話說, 這是一個鍊式結構, 也就是區塊鏈的由來.

神功第五層  
區塊鏈節節扣, 
最長鏈掃乾坤

這一層會初始化第一個區塊, 並據此, 生產一個鍊式結構, 形成區塊鏈. 區塊鏈可以存儲在  Array  結構中, 在存儲的過程中, 還要驗證區塊是否有效.

初始化區塊  class Block

def  initialize(prev_block, msg) 

  @msg = msg

  @prev_block_hash = prev_block.own_hash if prev_block
 
 mine_block!
   
end

挖礦, 最繁重的勞動是找  nonce

def  mine_block! 

 @nonce = calc_nonce

 @own_hash
= hash(full_block( @nonce ))

end

一個完整的區塊是這樣  compact  出來的

def  full_block(nonce)

   [ @msg , @prev_block_hash , nonce].compact.join 

end

初始化區塊鏈  class BlockChain
用  Array  存儲就可以啦:

def  initialize(msg) 
 
 @blocks
= []

 @blocks Block.new( nil , msg)

end

將區塊加入鏈條, 整個區塊鏈在不停的增長

def  add_to_chain(msg) 

 @blocks Block.new( @blocks .last, msg)    puts @blocks .last

end

一定要嚴格的驗證  block  是不是健康

def  valid? 

 @blocks .all? { |block| block.is_a?( Block ) } &&

    @blocks .all?(& :valid? ) &&
   
    @blocks .each_cons( 2 ).all? { |a, b| a.own_hash == b.prev_block_hash }
   
end


神功第六層  
六合之法, 融會貫通
朋克神教, 初現神通

所謂六合,“精氣神”為內三合,“手眼身”為外三合,

其用為“眼與心合,心與氣 合,氣與身合,身與手合,手與腳合,腳與胯合。”

全身內外,渾然一體。

此乃少林旁支韋陀門的武功,全守六合之法。

在第一層轉賬交易  class Transaction  中, 需要用私鑰對信息進行簽名

@signature = PKI .sign(message, priv_key) 

第一個挖出區塊, 會的到  500_000  大洋的獎勵.

def  self .create_genesis_block(pub_key, priv_key)

   genesis_txn = Transaction .new( nil , pub_key, 500_000 , priv_key) 

 Block .new( nil , genesis_txn)

end

驗證賬戶花錢是不是有效

def  all_spends_valid?

   compute_balances do |balances, from, to| 

   return false if balances.values_at(from, to).any? { |bal| bal 0 }

 end   true

end

將未知的節點加入  $PEERS , 保持網絡增長

if  PEER_PORT . nil ? 

 # You are the progenitor!   $BLOCKCHAIN = BlockChain .new( PUB_KEY , PRIV_KEY )

 else   # You're just joining the network.   $PEERS PEER_PORT

end

節點之間的處理數據, 先讀取  blockchain  和  peers , 然後更新他們

# @param blockchain # @param peers post '/gossip'  do  their_blockchain = YAML .load(params[ 'blockchain' ])

   their_peers = YAML .load(params[ 'peers' ])

   update_blockchain(their_blockchain)

   update_peers(their_peers)   

 YAML .dump( 'peers' => $PEERS , 'blockchain' => $BLOCKCHAIN )

end

處理接受到的區塊, 我們只關心他是不是更長

def  update_blockchain(their_blockchain)   

 return if their_blockchain. nil ?

  return if $BLOCKCHAIN && their_blockchain.length $BLOCKCHAIN.length
 
  return unless their_blockchain.valid?   $BLOCKCHAIN = their_blockchain
 
  end

更新  peers , 只要以前沒有的  peer :

def  update_peers(their_peers) 

  $PEERS = ( $PEERS + their_peers).uniq

end

發送錢, 需要先得到對方的  pub_key , 然後從我的  pub_key  向他發送  amount .

# @param to (port_number) # @param amount post '/send_money'  do  to = Client .get_pub_key(params[ 'to' ])

   amount = params[ 'amount' ].to_i 

  $BLOCKCHAIN .add_to_chain( Transaction .new( PUB_KEY , to, amount, PRIV_KEY ))

  'OK. Block mined!'

end

區塊鏈放進  Gossip  網絡, 將各個功能組合到一起, 一個可運行的  Block Demo  就成功了.

這個  Demo  在  Github  上, 油管上配有視頻,

https://github.com/Haseeb-Qureshi/lets-build-a-blockchain

最後祝大家練功順利, 早日大成.


推薦

知識星球

   待字閨中官方區塊鏈知識星球,已經有接近500人加入星球,期待你的加入。      一起討論區塊鏈、數字貨幣。 做區塊鏈社區中的精品良心社區。

往期推薦:

  1. 扒一下互聯網公司的區塊鏈佈局

  2. 數字貨幣可能是一場虛幻

  3. 區塊鏈溯源防偽,別逗了

  4. 飯票是一場騙局,也是一個開始

  5. 用偽代碼理解DPoS

  6. 區塊鏈大規模應用,技術上必須回答的問題

  7. 區塊鏈革命,聊聊心態、炒幣和投資

  8. 區塊鏈革命,你能參與些什麼?

  9. 大跌中,是時候回歸區塊鏈與數字貨幣的本質

  10. 公開,公正,公平,區塊鏈的試金石

  11. “美國共識”—區塊鏈最新的共識算法

  12. 沒有激勵機制的Algorand如何改變區塊鏈技術

  13. 區塊鏈創新離不開一流的工程技術能力

  14. 唯有技術之路你自己可以把握

  15. ETH 800 億美元市值的幕後功臣 – ERC20

  16. 區塊鏈算法:Markov Chain Monte Carlo (MCMC)

未經允許不得轉載:頭條楓林網 » 用Ruby實現一個最簡的區塊鏈