Fabric学习(四)----编写简单的GO链码

Fabric官方文档:https://hyperledger-fabric.readthedocs.io/en/release-2.2/

API文档:https://pkg.go.dev/github.com/hyperledger/fabric-chaincode-go/shim#Chaincode

0.前言

在本节中,完成了一个简单的fabric中GO链码的编写,实现数据存储和数据查看,并进行了测试。

1.编写链码

编写链码主要分为如下几步:

  • 开发前准备
  • 编写init函数
  • 编写Invoke函数
  • 编写业务函数

接下来一步一步实现吧!

1.1开发前准备

首先需要明确一点,单纯的链码开发并不需要额外的环境,它只需要GO语言开发环境的就可以直接进行开发和测试。而之前配置的fabric环境主要用于组件网络以及链码的部署,本节不做额外考虑。

让我们进入正题吧!首先,新开一个项目:

//新建目录
mkdir fabric_test
cd fabric_test
//创建编写代码的源文件
go mod init
touch test.go

然后在代码中导入必须的包,和一个必须的结构体:

package main
import (
   "github.com/hyperledger/fabric-chaincode-go/shim"
   "github.com/hyperledger/fabric-protos-go/peer"
)
// 作为 Chaincode shim 方法的接收者
type TestChaincode struct {
}

这两个包中,包含了fabric区块链的大部分API,通过调用API即可完成存储、查看等各种功能。而TestChaincode结构体是必须的(名字可以自己指定), 作为 Chaincode shim 方法的接收者。

查看官方文档可知,ChaIncode接口包含init方法和invoke方法,链码必须要实现这个接口,因此我们要实现Init和invoke函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JS4b1J0w-1676978416413)(https://gitee.com/yu88888/myimage/raw/master/image/image-20211225192909374.png)]

1.2 Init函数的编写

Init方法在初始化链码的时候调用,我们可以在这个方法里面写一些初始化需要的函数,注意,Init函数也是可以接受参数的,接下来写个简单的Init函数吧!

func (t *TestChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
   // 获取参数
   args := stub.GetStringArgs()
   if len(args) != 2 {
      return shim.Error("Incorrect arguments. Expecting a key and a value")
   }
   // 通过调用stub.PutState()来存储参数
   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)
}

1.3 Invoke函数的编写

在链码每次被调用的时候都会调用Invoke函数,在编写Invoke函数时,普遍的方法是先获取方法名和参数,然后根据方法名,来调用不同的业务方法,在本例中,有set方法和get方法。

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 if fn == "get"{ 
      result, err = get(stub, args)
   }
   if err != nil {
      return shim.Error(err.Error())
   }
   return shim.Success([]byte(result))
}

1.4 编写业务函数

本小节主要实现最简单的set和get函数。

// Set stores the asset (both key and value) on the ledger. If the key exists,
// it will override the value with the new one
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
   if len(args) != 2 {
      return "", fmt.Errorf("Incorrect arguments. Expecting a key and a 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
}

// Get returns the value of the specified asset key
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
}

最后还需要一个main函数。

// main function starts up the chaincode in the container during instantiate
func main() {
   if err := shim.Start(new(SimpleAsset)); err != nil {
      fmt.Printf("Error starting SimpleAsset chaincode: %s", err)
   }
}

2.进行测试

测试使用的是shimtest 包,其文档为https://pkg.go.dev/github.com/hyperledger/[email protected]/shimtest

单元测试不需要启动任何网络节点,通过测试文件就可以在本地对链码中的接口进行调用测试,其原理就是利用shimtest包中的API,新建一个MockStub类

猜你喜欢

转载自blog.csdn.net/doreen211/article/details/129148415