zoukankan      html  css  js  c++  java
  • 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接口。另外还有个main函数,作为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

  • 相关阅读:
    数组类型
    约瑟夫环问题
    const在c和c++中地位不同
    Makefile学习之路——4
    单链表综合操作
    算法初探——大O表示法
    数据结构实用概念
    Makefile学习之路——3
    翻转字符串
    Makefile学习之路——2
  • 原文地址:https://www.cnblogs.com/flythinking/p/9883699.html
Copyright © 2011-2022 走看看