超級賬本的開發,首先來了解一下 Chaincode 的概念,然後介紹如何開發 Chaincode,如何將 Chaincode 部署到 Fabric 中,以及如何使用 Chaincode。
Chaincode,中文一般稱為鏈碼,是超級賬本中的智能合約,本質上就是一段計算機語言實現的程序。Chaincode 是超級賬本的重要組成部分,一般用 Go 語言編寫,也支持用 Java、JavaScript 等計算機語言來進行編寫。本書中的 Chaincode 使用 Go 語言編寫。
那 Chaincode 是如何運行的呢?Chaincode 編寫完成後需要進行編譯並部署到超級賬本上。部署完成後,Chaincode 運行在一個受保護的 Docker 容器當中,與背書節點的運行互相隔離。超級賬本通過 Chaincode 實現對賬本數據的讀取和修改操作,同時也會把操作的日誌保存到超級賬本的數據庫中。由一個 Chaincode 創建的狀態僅限於該 Chaincode 有權限訪問,不能由另一個 Chaincode 直接訪問。然而,在同一個超級賬本中,給定適當的權限,一個 Chaincode 可以調用另一個 Chaincode 來訪問其創建的狀態。
Chaincode 的生命周期包括打包、安裝、實例化和升級這四個階段,具體過程會在下面實例中講解。
開發 Chaincode 就是實現特定的接口,這個接口包括兩個方法 ——Init()方法和 Invoke()方法。這兩個方法的作用如下:當 Chaincode 接收 instantiate 或 upgrade 事務時,會調用 Init()方法,以便 Chaincode 可以執行任何必要的初始化,包括應用程序狀態的初始化;Invoke()方法是為了響應接收調用事務來處理事務提案。
下面實現一個最簡單的 Chaincode,這個例子中的作用就是展示如何開發 Chaincode 以及 Chaincode 的執行流程。在這個 Chaincode 中不對數據進行處理,調用方法後直接返回就可以了,所以在編寫 Init()方法和 Invoke()方法的主體功能時返回空值就可以了。代碼如下:
其中 main 函數是 Go 程序執行的入口函數,當在節點部署 Chaincode 時,就會執行 main 函數裡面的內容。main 函數中第 1 句 Err:=shim.Start(new(SampleChaincode))會啟動示例的 Chaincode,如發生錯誤會輸出啟動失敗的信息,否則就會輸出成功運行的信息。
在上面的示例中實現了 Chaincode 的 3 個方法,依次為 Init、Query 和 Invoke。下面依次來了解下這 3 個方法的作用
●Init()方法。Init()方法會在 Chaincode 首次部署實現到區塊鏈時由各個節點調用,此方法可用於實現任何與初始化、引導或設置相關的任務。
●Query()方法。只要在區塊鏈上執行任何查詢操作,就會調用 Query()方法。Query()方法不會修改區塊鏈的狀態,因此它不會在交易上下文內運行。如果嘗試在 Query()方法內修改區塊鏈的狀態,將出現一個錯誤。另外,因為此方法僅用於讀取區塊鏈的狀態,所以對它的調用不會記錄在區塊鏈上。
●Invoke()方法。只要修改區塊鏈的狀態,就會調用 Invoke()方法,所以所有對區塊鏈進行的更新或刪除操作都應封裝在 Invoke 方法內。因為此方法將修改區塊鏈的狀態,所以超級賬本會自動創建一個交易上下文,以便此方法在其中執行。對此方法的所有調用都會在區塊鏈上記錄為交易,這些交易最終被寫入區塊中。
實現了上述的代碼後就可以操作這個 Chaincode。Fabric 提供了 4 個命令管理 Chaincode,分別是打包(package)、安裝(install)、實例化(instantiate)、升級(upgrade)。首先通過 package 命令打包 Chaincode,然後用 install 命令安裝 Chaincode,再通過 instantiate 實例化 Chaincode。如果需要升級 Chaincode,則需要先安裝新版本的 Chaincode,再通過 upgrade 命令對其進行升級。
在未來的版本中,官方也正在考慮添加 stop 和 start 命令禁用和重新啟用 Chaincode,而不必卸載它。在成功安裝並實例化了一個 Chaincode 之後,Chaincode 就處於活躍中(正在運行)。在安裝完畢後,也可以在任何時間都對 Chaincode 進行升級,如圖
Chaincode 有兩種安裝方式,一是直接安裝源代碼,二是通過 package 命令打包並簽名生成打包文件,然後再通過 install 命令進行安裝生成的打包文件。
以上就是 Chaincode 的開發和使用過程,最後再花一小節補充說明一下 Chaincode 的打包過程。
為了方便對 Chaincode 進行管理和簽名認證,通常需要對 Chaincode 進行打包操作。所以本節專門對 Chaincode 的打包過程進行詳解。
Chaincode 包由 3 部分組成,包括 Chaincode 代碼本身、一個可選的實例化策略和擁有 Chaincode 實體的一組簽名。其中區塊鏈上 Chaincode 被實例化進行交易的時候,可被 Chaincode 對應的實例化策略驗證。
簽名有以下作用。
●建立 Chaincode 的所有權
●對包的內容進行驗證。
●檢測包是否篡改。
打包 Chaincode 有兩種方式。第 1 種方式是當 Chaincode 有多個所有者的時候,需要讓 Chaincode 包被多個所有者簽名。在這種情況下需要創建一個需要簽名的 Chaincode 包,這個包依次被每個所有者簽名。第 2 種就比較簡單了,在已簽名的節點上用 install 命令進行打包操作即可。
以上就是關於 Chaincode 的內容,下面開始進入超級賬本的實際開發。
第 1 個實例是構建一個本地的 Fabric 網絡,通過本案例可以學習如何基於超級賬本構建一個簡單的區塊鏈網絡,並與這個網絡進行基本的交互操作,例如查詢和更新超級賬本的區塊鏈數據。
超級賬本的本地環境安裝一節中已經下載了 Fabric Samples 的代碼,在這些示例代碼中一個名為 “first-network” 的文件夾,整個文件夾是一個完整的 Fabric 項目示例,實現了一個 Fabric 網絡,這個 Fabric 網絡中包含多個節點,以及一個命令行工具。下面使用這個示例構建第 1 個 Fabric 網絡。
進入 fabric-network 的子目錄 first-network 中,可以看到該目錄下有一個名為 byfn.sh 的腳本文件。這個腳本文件中有著很完備的注釋說明,執行 “./byfn.shh” 可以看到這個腳本文件的使用說明,包括如何啟動和停止等操作 Fabric 網絡的命令,如圖
下面開始構建這個簡單的 Fabric 網絡。使用命令 “./byfn.sh -m generate” 來生成網絡所需的證書和創世區塊,命令執行的過程中需要進行一些配置,這裡使用默認配置,在命令行工具中輸入 “Y” 確認即可,如圖
可以看到在這個過程中,先是用 cryptogen 工具生成各種網絡實體的證書和密鑰(cryptogen 是 Fabric 項目中提供的用來生成需要的證書的工具),這些證書是身份的代表,它們允許在網絡中進行交流和交易時進行簽名 / 驗證身份;然後生成一個 genesis block(創世區塊),用於引導 orderer 節點進行排序服務;最後生成 Channel 所需要的交易配置信息並保存到文件中。
若要關閉這個網絡可以使用./byfn.sh -m down 命令進行操作,如圖所示。
在啟動這個 Fabric 網絡後,我們就可以與這個網絡的交互。交互的內容包括對網絡中管道(channel,是指在 Fabric 網絡中的通道,用來連接網絡中的節點和隔離其他非相關的節點)的管理和對 Chaincode 的操作,從而更深入地認識 Fabric 網絡。與 Fabric 網絡交互的方式是可以通過命令行工具(CLI)調用 Fabric API 實現。
使用 CLI 需要先進入 CLI 容器(一個包含命令行工具 CLI 的 docker 容器,可以理解為一個可運行 CLI 的獨立環境),進入容器的命令是 “docker exec-it cli bash”,如圖
進入 CLI 容器後可以看到容器中的內容並對 Fabric 網絡進行查詢和更新操作。在 CLI 中使用的命令主要分為兩種,一種是和 channel 有關的命令,另外一種是和 Chaincode 有關的命令。
(1)和 channel 有關的命令
和 channel 有關的命令如下。
●創建 channel。
進入 CLI 容器,可以通過如下命令來創建通道:
peer channel create -o orderer.example.com:7050 -c mychannel -f./channel-artifacts/channel.tx --tls true --cafile/opt/gopath/src/github.com/hyperledger/ fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer. example.com/msp/tlscacerts/tlsca.example.com-cert.pem
其中的參數含義如下。
●-o orderer.example.com:7050:指定了 orderer 的服務定義,用作排序服務。
●-c mychannel:要創建通道的名字。
●-f./channel-artifacts/channel.tx:指定由 configtxgen 等工具生成的配置交易文件,用於提交給 orderer 節點。
●--tls true:與 orderer 通信是否啟動 TLS。
--cafile/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem:指定 orderer 節點的 TLS 證書,該證書為 PEM 格式。
●加入 channel。
加入 channel 的命令是 peer channel join -b mychannel.block,其中 - b 是區塊路徑,這裡指向包含創世區塊的文件路徑。
●列舉所有 channel。
列舉所有 channel 的命令是 peer channel list。
●更新 channel。
更新 channel 的命令是 peer channel update -o orderer.example.com:7050 -c mychannel -f./channel-artifacts/Org1MSPanchors.tx --tls true --cafile /opt/gopath/src/github.com/ hyperl-edger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlsc-acerts/tlsca.example.com-cert.pem,參數與創建 channel 的類似。
(2)和 Chaincode 有關的命令
和 Chaincode 有關的命令如下。
●安裝 Chaincode:peer chaincode install [flags]。
●實例化 Chaincode:peer chaincode instantiate [flags]。
●調用 Chaincode:peer chaincode invoke。
●打包 Chaincode:peer chaincode package。
●查詢 Chaincode:peer chaincode query。
●對 Chaincode 進行簽名:peer chaincode signpackage。
●更新 Chaincode:peer chaincode upgrade。
其中主要可以使用的參數如下。
●-C:channel ID。
●-c:JSON 字串的鏈碼構造函數消息(默認 “{}”)。
●-h:幫助。
●-l:編寫 Chaincode 的語言,默認 “golang”。
●-n:Chaincode 名稱。
●-p:Chaincode 路徑。
●-v:Chaincode 版本。
●-o:orderer 節點。
下面通過 Chaincode 命令查詢和更新超級賬本。
查詢和更新超級賬本#
在 CLI 容器中,先使用 query 對 a 和 b 的餘額進行查詢操作(其中 a 和 b 是在使用 byfn.sh-m up 命令啟動網絡時自動創建的兩個賬戶),可以看到 a 有 90,而 b 有 210,如圖
然後從 b 賬戶轉 80 到 a 賬戶。這個交易將創建一個新的區塊並更新區塊鏈。操作命令如圖
由上圖可以看到操作成功,此時在查詢 a 賬戶和 b 賬戶,應該可以看到 a 賬戶有 170,b 賬戶有 130,如圖
以上就是通過 Chaincode 查詢和更新超級賬本的方法。