2017年4月10日

Hyperledger: blockchain 超級帳本

自 bitcoin 開始,blockchain被視為是下一代新的技術革新,因為本質為去中心化的一個資料庫,也就是用了 P2P 的技術,來解決原本集中式的網路架構,所造成的網路互信問題。

一般認為 blockchain 會是一項改變世界的創新技術,但也由於這樣分散式的架構,所有參與這個 blockchain 的網路節點,都會是一個參與驗證的獨立個體,每一個節點的運算速度跟網路頻寬,也間接影響了 blockchain 所能提供的每秒最大交易數量(tps transaction per second)的速度。

因此 blockchain 由 bitcoin 時代的 public blockchain,演進出現了 federated blockchain 以及 private blockchain,速度最快的 private blockchain 也是最貼近企業應用的一種 blockchain。

事實上也有人認為私有鏈並不是 blockchain,就像是傳統的資料庫一樣,只是換了一個 blockchain 的包裝,這就像是一種既有的分散式帳本技術而已,可以參閱這篇文章的討論:全面認識區塊鏈:公有鏈vs私有鏈,關於 blockchain 的企業應用目前並沒有很明確的答案。

Hyperledger

Hyperledger 是 2015 年 12 月由 Linux 基金會聯合了三十家公司,合作的一個 private blockchain 專案,它可說是繼 bitcoin,ethereum 之後,最受關注的一個 blockchain 專案。

在超級賬本聯盟成立之前,IBM公司就已經開源了一個 Open Blockchain,OBC 專案。在聯盟成立之後,IBM把OBC項目約 44000 行代碼貢獻給了Linux基金會,這部分代碼成為了Fabric的代碼的主要組成部分。在2016年3月的一次黑客松編程活動中,Blockstream和數字資產兩個成員公司把各自的區塊鏈功能代碼融合到OBC中,最終建立了Fabric的雛形,也就是Fabric項目進入孵化階段的基礎代碼。

目前有三個帳本平台項目

  • fabric:包括 fabric 和 fabric-api、fabric-sdk-node、fabric-sdk-py 等,目標是區塊鏈的基礎核心平台,支持 pbft 等新的 consensus 機制,支持權限管理,最早由 IBM 和 DAH 發起;
  • sawtooth Lake:包括 arcade、core、dev-tools、validator、mktplace 等。是 Intel 主要發起和貢獻的區塊鏈平台,支持全新的基於硬體晶片的共識機制 Proof of Elapsed Time(PoET)。
  • Iroha:賬本平台項目,主要由 Soramitsu 發起和貢獻。

測試 hyperledger smartcontract

ref: 從零開始,5分鐘創建並玩轉屬於自己的區塊鏈(圖文攻略)

IBM中國研究院開發的 SuperVessel 平臺提供了給區塊鏈愛好者、開發者的區塊鏈開發測試環境。通過該平臺,用戶能夠免費、超快速創建基於Hyperledger Fabric的多節點區塊鏈。

  1. SuperVessel 區塊鏈 申請帳號

  2. 點中間的 MY DASHBOARD

  3. 點擊 Chain -> Apply a new chain,產生一個 blockchain,我們選擇 pbft 演算法,4 個 nodes

  4. 主畫面是剛剛建立的 test pbft blockchain

  5. Smart Contract 裡面已經有兩個 sample: map 跟 chaincode_example02

  6. 回到 test pbft,點右下角的 deploy,選擇 chaincode_example02,任意一個 instance name,init a 與 b 分別有 100 及 200 元

  7. 點 invoke,function: transfer 就是轉帳,由 a 帳戶轉給 b 50 元

  8. 可以 Query a 或 b 帳戶目前的餘額

  9. 帳戶異動的動作都會產生一個新的 block

如果在同一個 blockchain 部署兩個 smart contact,blocks 上的區塊是會累積起來的。

以 docker 測試 hyperledger

ref: 區塊鏈技術指南

用 dokcer 下載 hyperledger images

$ docker pull hyperledger/fabric-peer:x86_64-0.6.1-preview \
  && docker pull hyperledger/fabric-membersrvc:x86_64-0.6.1-preview \
  && docker pull yeasy/blockchain-explorer:latest \
  && docker tag hyperledger/fabric-peer:x86_64-0.6.1-preview hyperledger/fabric-peer \
  && docker tag hyperledger/fabric-peer:x86_64-0.6.1-preview hyperledger/fabric-baseimage \
  && docker tag hyperledger/fabric-membersrvc:x86_64-0.6.1-preview hyperledger/fabric-membersrvc

可使用 noops 或是 PBFT 兩種不同的一致性演算法

如果使用 noops 可以只開一個節點

$ docker run --name=vp0 \
    --restart=unless-stopped \
    -it \
    -p 7050:7050 \
    -p 7051:7051 \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -e CORE_PEER_ID=vp0 \
    -e CORE_PEER_ADDRESSAUTODETECT=true \
    -e CORE_NOOPS_BLOCK_WAIT=10 \
    hyperledger/fabric-peer:latest peer node start

PBFT 是比較常用的一致性演算法,只少需要四個節點

在 yeasy/docker-compose-files 有幾個 template,可以用 git 下載

git clone https://github.com/yeasy/docker-compose-files

在 docker-compose-files/hyperledger/0.6/pbft 目錄中有以下這些 templates

  1. 4-peers.yml: 啟動四個 PBFT peer 節點
  2. 4-peers-with-membersrvc.yml: 啟動 4 個 PBFT peer 節點 + 1 個 CA 節點,並啟用 CA 功能。
  3. 4-peers-with-explorer.yml: 啟動 4 個 PBFT peer 節點 + 1 個 Blockchain-explorer,可以通過 Web 界面監控集群狀態。
  4. 4-peers-with-membersrvc-explorer.yml: 啟動 4 個 PBFT peer 節點 + 1 個 CA 節點 + 1 個 Blockchain-explorer,並啟用 CA 功能。

可用 docker-compose 快速啟動一個 4 個 PBFT 節點的集群

$ docker-compose -f 4-peers.yml up

如果要自己一個一個慢慢建立節點

# vp0 初始的探測節點 (10.0.0.1)
$docker run --name=vp0 \
    --net="host" \
    --restart=unless-stopped \
    -it --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -e CORE_PEER_ID=vp0 \
    -e CORE_PBFT_GENERAL_N=4 \
    -e CORE_LOGGING_LEVEL=debug \
    -e CORE_PEER_ADDRESSAUTODETECT=true \
    -e CORE_PEER_NETWORKID=dev \
    -e CORE_PEER_VALIDATOR_CONSENSUS_PLUGIN=pbft \
    -e CORE_PBFT_GENERAL_MODE=batch \
    -e CORE_PBFT_GENERAL_TIMEOUT_REQUEST=10s \
    hyperledger/fabric-peer:latest peer node start

# vp1 ~ vp3
$ NAME=vp1
$ ROOT_NODE=10.0.0.1
$ docker run --name=${NAME} \
    --net="host" \
    --restart=unless-stopped \
    -it --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -e CORE_PEER_ID=${NAME} \
    -e CORE_PBFT_GENERAL_N=4 \
    -e CORE_LOGGING_LEVEL=debug \
    -e CORE_PEER_ADDRESSAUTODETECT=true \
    -e CORE_PEER_NETWORKID=dev \
    -e CORE_PEER_VALIDATOR_CONSENSUS_PLUGIN=pbft \
    -e CORE_PBFT_GENERAL_MODE=batch \
    -e CORE_PBFT_GENERAL_TIMEOUT_REQUEST=10s \
    -e CORE_PEER_DISCOVERY_ROOTNODE=${ROOT_NODE}:7051 \
    hyperledger/fabric-peer:latest peer node start
測試 example02 smart contract

使用 docker-compose 快速啟動一個 4 個 PBFT 節點的集群,如果剛剛有啟動過,就先把舊的 containers 刪除

$ docker-compose -f 4-peers.yml up

進入 pbftvp01

$ docker exec -it pbft_vp0_1 bash

部署 example02 chain code,就是 init a 100 元 b 200 元兩個帳戶

# peer chaincode deploy -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'

03:42:46.851 [chaincodeCmd] chaincodeDeploy -> INFO 001 Deploy result: type:GOLANG chaincodeID:<path:"github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"init" args:"a" args:"100" args:"b" args:"200" >
Deploy chaincode: ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539
03:42:46.852 [main] main -> INFO 002 Exiting.....

得到的 codecode id,放在環境變數中

$ CC_ID=ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539

查詢 a 帳戶的餘額

$ peer chaincode query -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'

03:45:54.865 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > >
Query Result: 100
03:45:54.865 [main] main -> INFO 002 Exiting.....

a 轉帳 50 元給 b

$ peer chaincode invoke -n ${CC_ID} -c '{"Function": "invoke", "Args": ["a", "b", "50"]}'

03:46:58.806 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully invoked transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"invoke" args:"a" args:"b" args:"50" > > (b63aead7-154c-42bb-8ae5-3a880f305f9e)
03:46:58.806 [main] main -> INFO 002 Exiting.....

查詢 a 帳戶的餘額

$ peer chaincode query -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'

03:47:25.763 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > >
Query Result: 50
03:47:25.763 [main] main -> INFO 002 Exiting.....

測試 權限管理

啟動帶成員管理的 PBFT 集群,包含 4 個 PBFT peer 節點 + 1 個 CA 節點 + 1 個 Blockchain-explorer,並啟用 CA 功能。

docker-compose -f 4-peers-with-membersrvc.yml up

連線到 pbftvp01

docker exec -it pbft_vp0_1 bash

以內建帳號 jim (密碼為: 6avZQLwcUe9b)登錄到系統

# peer network login jim
08:09:30.235 [networkCmd] networkLogin -> INFO 001 CLI client login...
08:09:30.236 [networkCmd] networkLogin -> INFO 002 Local data store for client loginToken: /var/hyperledger/production/client/
Enter password for user 'jim': 6avZQLwcUe9b
08:11:18.446 [networkCmd] networkLogin -> INFO 003 Logging in user 'jim' on CLI interface...
08:11:18.881 [networkCmd] networkLogin -> INFO 004 Storing login token for user 'jim'.
08:11:18.882 [networkCmd] networkLogin -> INFO 005 Login successful for user 'jim'.
08:11:18.882 [main] main -> INFO 006 Exiting.....

先安裝 curl

apt-get update
apt-get install curl

用 POST 的方式呼叫 register

$ curl -X POST -H 'Content-Type: application/json' -d '{"enrollId": "jim","enrollSecret": "6avZQLwcUe9b"}' http://localhost:7050/registrar

{"OK":"User jim is already logged in."}

接下來 chaincode 的部屬跟呼叫都需要再加上 -u 指定帳號。

# peer chaincode deploy -u jim -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'

08:20:35.263 [chaincodeCmd] getChaincodeSpecification -> INFO 001 Local user 'jim' is already logged in. Retrieving login token.
08:20:38.338 [chaincodeCmd] chaincodeDeploy -> INFO 002 Deploy result: type:GOLANG chaincodeID:<path:"github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"init" args:"a" args:"100" args:"b" args:"200" >
Deploy chaincode: ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539
08:20:38.338 [main] main -> INFO 003 Exiting.....

紀錄 chaincode ID

$ CC_ID=ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539

查詢帳戶 a 的餘額為 100

$ peer chaincode query -u jim -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'

08:22:25.600 [chaincodeCmd] getChaincodeSpecification -> INFO 001 Local user 'jim' is already logged in. Retrieving login token.
08:22:25.876 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 002 Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > secureContext:"jim" >
Query Result: 100
08:22:25.876 [main] main -> INFO 003 Exiting.....

用 REST 方式進行 query

$ curl -X POST -H 'Content-Type: application/json' -d '
{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
      "type": 1,
      "chaincodeID":{
          "name":"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539"
      },
      "ctorMsg": {
         "function":"query",
         "args":["a"]
      },
    "secureContext": "jim"
  },
  "id": 3
}
' http://localhost:7050/chaincode

{"jsonrpc":"2.0","result":{"status":"OK","message":"c62697b9-5ade-41ff-99ef-0733cf99c05d"},"id":3}

查詢 block 資訊

$ curl -X GET http://localhost:7050/chain/blocks/2

{"stateHash":"QkIbllrDhpZ1+ZGCTwbu83CEnR9oA8/fECHDCvYNz6wjdpxvCS/aTsG24NbDAhMtHQmhq12yhoCYmSLgGvLm+A==","previousBlockHash":"DnwB438SiFir+5AoeUPLup8l1qEZN1ddPdgOPr2BnbBQT4W0ENOPym1o4c0IkAHC+xuQiw68cXkcSjcrZi1CJg==","consensusMetadata":"CAI=","nonHashData":{"localLedgerCommitTimestamp":{"seconds":1482913592,"nanos":719911090},"chaincodeEvents":[{}]}}

References

區塊鏈科技趨勢與應用

專訪R3聯盟高層:分散式分類帳和區塊鏈有何不同?

中国区块链技术和应用发展白皮书 2016

五個問答讓你秒懂區塊鏈原理及應用

最具商用價值的開源區塊鏈項目:超級賬本

hyperledger 官方網站

hyperledger fabric doc

區塊鏈組織-超級賬本(Hyperledger)的簡介

區塊鏈在中國:IBM HyperLedger

Hyperledger智能合约Hello World示例程序

學習鏈碼

在开发环境下编写,运行,测试chaincode

hyperledger fabric本地開發環境mac部署

Hyperledger fabric 開發環境搭建