1024 節獻禮: simple chain

作者: 陳天(ArcBlock 研發副總裁)
前兩週上線了我們為 Cybermiles 提供的 supernode,因為 Cybermiles 主網使用了 Tendermint,於是上週便研究了一下 Tendermint,邊學邊寫了個 slides 介紹 Tendermint。
Tendermint 是一個脫胎於 PBFT 的 consensus engine,並在此之上構建了一個 Application BlockChain Interface (ABCI),讓 blockchain 的開發者可以關注於如何提供服務,以及維繫服務的狀態,而把如何達成共識,如何管理 mempool,如何進行安全的 p2p 通訊這樣的瑣事交給 Tendermint 來處理。Tendermint 自身是 golang 撰寫的,其 ABCI 介面用 protobuf 實現,並使用 raw TCP 或者 http2 (gRPC) 和 application layer 通訊。

週日,閒來無事,想用 tendermint 做點東西。無奈 tendermint 沒有提供 elixir 的 ABCI 實現,社群的 erlang 實現又缺失一些東西,且我很不喜歡 erlang 下用 Record 來描述 protobuf 的方式,於是用 Tony 的 protobuf 函式庫,寫了個 elixir 的 ABCI 實現,放在 github.com/arcblock/ex_abci 上,並隨後實現了 Tendermint 自身提供的 counter example app - 用區塊鏈的不可篡改性來維護一個全網唯一的計數器。
使用 ex_abci,counter app 的核心程式碼也就幾十行,就是實現 info,check_tx,deliver_tx 幾個介面即可:

這樣的 app 當 hello world 還可以,用來驗證 Tendermint 是否靠譜,本身並不靠譜。Tendermint 還提供了一個 kv store 的 example,也沒有 get 到區塊鏈的核心要素,於是我便萌生了搞一個足夠簡單,最好能在幾百行內演示區塊鏈技術的 Simple Chain。那什麼算是區塊鏈的核心要素呢,我覺得是這幅圖 - Merkle Patricia Tree (MPT):

這是以太坊保存其 World State 的核心 - 我相信我的讀者們了解 patricia tree (prefix tree, radix tree, 或者叫 trie),有一些區塊鏈知識的讀者應該知道 merkle tree,MPT 結合二者,組織出一個自帶驗證的 persistent data structure(函數式程式語言保存 list / map 的方式),關於 MPT 和以及上圖,我們的工程師丁沛靈同學在上次北京 Hackathon 有一個精彩的講座,感興趣的同學可以去 youtube arcblock channel 上找:ArcBlock's Introduction to Blockchain,在 37 分鐘附近開始講 MPT,大約 10 分鐘,非常之深入淺出。篇幅有限,我這裡就不詳細展開。
關於 Simple Chain,產品上我是這麼考慮的:
- 帳號系統相容以太坊
- 完整使用 Tendermint 的全部介面,並探索它們的意義
- chain 的狀態使用 MPT 保存,並將每個 block commit 後的 state root 提交給 Tendermint
- chain 能夠具有基本的容錯 - 比如 tx 執行到一半,crash 了,可以恢復到上一個 block 的 state 繼續往下執行
- Transaction 使用簡化版本的 Ethereum tx,一個 TX 只包含 from, to, nonce, total 和 pub key
- MPT 裡保存類似 Ethereum 的 account,每個 account 有自己的 balance,nonce 和 num_txs
- client RPC 直接整合在 Wallet 模組裡,方便演示
花了兩天的功夫,一個粗糙的,未經過多節點測試的版本終於實現了,原始碼見:ex_abci/examples/simple_chain。我們談談其主要對外介面:
- Wallet.new: 產生離線帳號
- Wallet.declare: 每個 Wallet 第一次可以讓系統給自己打 10000 個 token,這個主要方便測試
- Wallet.transfer:一個帳戶給另一個帳戶打錢。兩方的 address 對應的 account 會在 chain 的 MPT 裡更新,每個 block commit 之後,MPT root,也就是 app state 會寫入 block header。
- Wallet.info / Wallet.chain_info:存取 account 的資訊 / chain 的資訊
下面是執行時的整個過程。
初始化:

Wallet 狀態:

轉帳:



Tendermint block:

轉帳結束後的狀態:

這個 Simple Chain 主要使用到的技術:
- Tendermint 和 ex_abci,這是自然
- Elixir 下的 MPT 實現:merkle_patricia_tree
- Tony 的 protobuf 實現。我們在 MPT 裡儲存 account,其 value 也是用 protobuf 定義的
- keccakf1600:ethereum 的 sha3 的實現,用來產生 account address 和各種需要 hash 的場合(注意,我們這裡並沒有使用 double hash)
- libsecp256k1:ECDSA 的實現,主要用來產生 wallet,以及 transaction 的 sign 和 verify
目前程式碼量在 400 行內,基本上一目了然,用來理解 Tendermint 和區塊鏈技術的基本邏輯再好不過。感興趣的讀者可以安裝 tendermint,下載 github.com/arcblock/ex_abci 嘗試。
本來這篇文章想趕在 1024 節前發的 - 昨晚(24 日)我處理 crash recovery 沒有處理好,今早開車穿越 90 號高速上的迷霧時,突然有了思路,所以文章發晚了。對這些技術感興趣的同學,可以在 https://www.arcblock.io/en/learning/(點擊「閱讀原文」)上面報名我們未來的 Tech Talk,以及關注 arcblock 的 youtube channel 獲取我們之前的知識分享。
祝大家 1024 節快樂!