1. 程式人生 > >Hyperledger Fabric ChainCode開發

Hyperledger Fabric ChainCode開發

預覽

Hyperledger Fabric的chaincode開發目前支援Go、Java、Node.js語言,下面以Go語言作為例子,我們先看下面的一個官方提供chaincode模板
···

package main

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

type SimpleAsset struct {

}

func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
   args := stub.GetStringArgs()
   if len(args) != 2 {
      return shim.Error("Incorrect arguments. Expecting a key and a value")
   }

   err := stub.PutState(args[0], []byte(args[1]))
   if err != nil {
      return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
   }
   return shim.Success(nil)
}

func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
     fn, args := stub.GetFunctionAndParameters()

     var result string
     var err error
     if fn == "set" {
       result, err = set(stub, args)
    }else {
      result, err = get(stub, args)
    }
    if err != nil {
      return shim.Error(err.Error())
    }
    return shim.Success([]byte(result))
}

func set(stub shim.ChaincodeStubInterface, args []string) (string, error)  {
   if len(args) != 2 {
      return "", fmt.Errorf("Incorrect arguments. Expecting a key and value")
   }

   err := stub.PutState(args[0], []byte(args[1]))
   if err != nil {
      return "", fmt.Errorf("Failed to set asset: %s", args[0])
   }
   return args[1], nil
}

func get(stub shim.ChaincodeStubInterface, args []string) (string, error)  {
   if len(args) != 1  {
      return "", fmt.Errorf("Incorrect arguments. Expecting a key")
   }
   value, err := stub.GetState(args[0])
   if err != nil {
      return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
   }
   if value == nil {
      return "", fmt.Errorf("Asset not found: %s", args[0])
   }
   return string(value), nil
}

func main() {
   if err := shim.Start(new(SimpleAsset)); err != nil {
      fmt.Printf("Error starting SimpleAsset chaincode: %s", err)
   }
}

···
我們下面具體看看上面這段程式碼做了什麼。
開發chaincode時我們要實現ChainCode介面,ChainCode裡面有Init和Invoke這兩個函式。我們在前7行匯入了需要的依賴。接著定義了一個名為SimpleAsset的結構體,這個結構體實現了ChainCode介面。

初始化chaincode

接下來,我們實現Init方法
···

func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
   args := stub.GetStringArgs()
   if len(args) != 2 {
      return shim.Error("Incorrect arguments. Expecting a key and a value")
   }

   err := stub.PutState(args[0], []byte(args[1]))
   if err != nil {
      return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
   }
   return shim.Success(nil)
}

···
該方法在chaincode例項化時被呼叫,可以根據實際需要做一些初始化資料的操作。需要注意的是在chaincode升級時這個Init方法也會被呼叫。

呼叫chaincode

接著,我們繼續看Invoke方法
···

func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
     fn, args := stub.GetFunctionAndParameters()

     var result string
     var err error
     if fn == "set" {
       result, err = set(stub, args)
    }else {
      result, err = get(stub, args)
    }
    if err != nil {
      return shim.Error(err.Error())
    }
    return shim.Success([]byte(result))
}

···
Invoke方法主要就是根據傳過來的具體引數呼叫chaincode的其他業務函式。如這裡,就是根據傳過來的引數fn,如果fn=="set"則呼叫下面的set函式來把資料儲存到區塊鏈上(若狀態資料庫的key存在則是修改操作)。如果fn=="get"則呼叫後面的get函式來獲取鏈上的資料。

shim.ChaincodeStubInterface

上面的chaincode模板中很多地方都用到了ChaincodeStubInterface這個介面,這個介面為我們編寫chaincode提供了大量的方法。在這裡只介紹幾個,想詳細瞭解,可查閱官方文件

獲得呼叫引數

上面的chaincode模板中Init方法用到了GetStringArgs()函式,Invoke方法中用到了GetFunctionAndParameters()函式。這兩個函式都是用來解析傳入的引數的,除了這兩個函式外,ChaincodeStubInterface介面還提供了另外幾種函式。

  • GetArgs() [][]byte 以byte陣列的陣列的形式獲得傳入的引數列表
  • GetStringArgs() []string 以字串陣列的形式獲得傳入的引數列表
  • GetFunctionAndParameters() (string, []string) 將字串陣列的引數分為兩部分,陣列第一個字是Function,剩下的都是Parameter
  • GetArgsSlice() ([]byte, error) 以byte切片的形式獲得引數列表

增刪改查狀態資料庫(State Database)

  • PutState(key string, value []byte) error 增改資料

由於狀態資料庫是個key-value資料庫,所以如果key存在就是修改操作,如果key不存在就是增加操作。value是經過JSON序列化後的字串

  • GetState(key string) ([]byte, error) 根據key獲取狀態資料庫資料
  • DelState(key string) error 根據key刪除狀態資料庫資料

參考連結
https://hyperledger-fabric.readthedocs.io/en/release-1.3/chaincode4ade.html
https://godoc.org/github.com/hyperledger/fabric/core/chaincode/shim#Chaincode
https://godoc.org/github.com/hyperledger/fabric/core/chaincode/shim#ChaincodeStubInterface