1. 程式人生 > >Fabric--區塊鏈應用開發

Fabric--區塊鏈應用開發

區塊鏈應用開發

簡介

數字貨幣曾是區塊鏈技術的唯一應用場景

對智慧合約的支援突破了場景限制, 豐富了區塊鏈應用的適用範圍, 可以支援多行業、大規模的商業應用

區塊鏈應用

區塊鏈應用: 一般由若干部署在區塊鏈網路中的智慧合約, 以及呼叫這些智慧合約的應用程式組成

使用者專注於與業務本身相關的應用程式

智慧合約則封裝了與區塊鏈賬本直接互動的相關過程, 被應用程式呼叫

智慧合約開發

智慧合約本質上是為了對上層業務邏輯進行支援且直接與賬本結構打交道, 處於核心位置.

所以設計得當可以簡化上層應用開發的過程

應用程式開發

應用程式通過呼叫智慧合約提供的方法介面實現業務邏輯, 可以使用JavaScript、Python、Go、Java等主流語言進行開發

鏈碼的原理

鏈碼延伸自智慧合約的概念, 支援使用主流高階程式語言實現

區塊鏈網路中的成員商定業務邏輯後, 可將業務邏輯程式設計到鏈碼中, 所有人遵守合約執行

鏈碼會建立一些狀態(state)並寫入賬本中。狀態帶有繫結到鏈碼的名稱空間,僅限於建立他的鏈碼使用,不能被其他鏈碼直接訪問。不過,在合適的範圍內,一個鏈碼也可以呼叫另一個鏈碼,間接訪問其狀態

鏈碼在Fabric節點上的隔離沙盒(目前為Docker容器)中執行, 並通過gRPC協議與節點進行互動

  • 呼叫鏈碼
  • 讀寫賬本
  • 返回響應
  • ……

Fabric中支援多種語言實現鏈碼,包括Golang、JavaScript、Java等

基本工作原理

  1. 首先使用者通過客戶端向Fabric的背書節點發出調用鏈碼的交易提案
  2. 節點對交易提案進行包括ACL許可權檢查在內的各種檢驗, 通過後則建立模擬執行這一交易的環境
  3. 之後, 節點和鏈碼容器之間通過gRPC訊息來互動, 模擬執行交易並給出背書結論
  4. 當鏈碼的程式碼邏輯需要讀寫賬本時,通過shim層傳送相應操作型別給節點, 節點本地操作賬本後返回響應訊息
  5. 客戶端收到足夠的背書節點的支援後, 便可以將這筆交易傳送給排序節點進行排序, 並最終寫入區塊鏈

鏈碼介面與結構

依賴包

鏈碼實現需要引入如下依賴包

  • “github.com/hyperledger/fabric/core/chaincode/shim”

    1. shim包提供了鏈碼與賬本互動的中間層
    2. 鏈碼通過shim.ChaincodeStub提供的方法來讀取和修改賬本狀態
  • “github.com/hyperledger/fabric/protos/peer”

    • peer.Response: 響應資訊

鏈碼介面

每個鏈碼都需要實現chaincode介面:

type Chaincode interface{
    Init(stub ChaincodeStubInterface) peer.Response
    Invoke(stub ChaincodeStubInterface) peer.Response
}

Init與Invoke方法

編寫鏈碼, 關鍵是實現Init與Invoke兩個方法

Init方法在鏈碼部署或升級時被呼叫, 完成初始化工作

對資料進行操作時, Invoke方法被呼叫, 因此響應呼叫或查詢的業務邏輯都需要在此方法中實現

必要結構

一個鏈碼的必要結構如下

package main

//引入必要的包
import(
    "fmt"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    "github.com/hyperledger/fabric/protos/peer"
)

//宣告一個結構體
type SimpleChaincode struct {

}

//為結構體新增Init方法
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response{
  //在該方法中實現鏈碼初始化或升級時的處理邏輯
  //編寫時可靈活使用stub中的API
}

//為結構體新增Invoke方法
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response{
  //在該方法中實現鏈碼執行中被呼叫或查詢時的處理邏輯
  //編寫時可靈活使用stub中的API
}

//主函式,需要呼叫shim.Start( )方法
func main() {
  err := shim.Start(new(SimpleChaincode))
  if err != nil {
     fmt.Printf("Error starting Simple chaincode: %s", err)
    }
}

鏈碼API

賬本狀態互動API

鏈碼需要將資料記錄在分散式賬本中.需要記錄的資料稱為狀態, 以K-V對的形式儲存

賬本狀態互動API可以對賬本狀態進行操作

GetState(key string) ([]byte, error) 通過Key來返回陣列的特定值

PutState(key string, value []byte) error 賬本中寫入特定的鍵和值

DelState(key string) error 從賬本中移除指定的鍵和值

GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error) 根據指定的範圍內的健值

GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error) 返回指定健的所有歷史值

GetQueryResult(query string) (StateQueryIteratorInterface, error) 對(支援富查詢功能的)狀態資料庫進行富查詢

交易資訊相關API

GetTxID() string 返回交易提案中指定的交易ID

GetTxTimestamp() (*timestamp.Timestamp, error) 返回交易建立的時間戳,這個時間戳是peer收到交易的當前時間

GetBinding() ([]byte, error) 返回交易的binding資訊

GetSignedProposal() (*pb.SignedProposal, error) 返回與交易提案相關的所有資料

GetCreator() ([]byte, error) 返回該交易的提交者的身份資訊

GetTransient() (map[string][]byte, error) 返回交易中不會被寫至賬本中的一些臨時資訊

引數API

GetArgs() [][]byte 返回呼叫鏈碼時交易提案中指定的引數

GetArgsSlice() ([]byte, error) 返回呼叫鏈碼時交易提案中指定的引數

GetFunctionAndParameters() (function string, params []string) 返回呼叫鏈碼時交易提案中指定的被呼叫的函式名稱及其引數

GetStringArgs() []string 返回呼叫鏈碼時指定的引數

-c ‘{“Args”:[“fn”, “param1”, “param2”, “paramN”]}’

示例(HelloWorld)

Init方法

  • 獲取引數並判斷引數長度是否為2
    • 引數: Key, Value
  • 呼叫PutState方法將狀態寫入賬本中
  • 如果有錯誤, 則返回
  • 列印輸出提示資訊
  • 返回成功

Invoke方法

  • 獲取引數並判斷長度是否為1
  • 利用第1個引數獲取對應狀態GetState(key)
  • 如果有錯誤則返回
  • 如果返回值為空則返回錯誤
  • 返回成功狀態