Hyperledger Fabric 链码的结构

版权声明:博客中的文章版权归博主所有,未经授权,禁止转载,转载请注明出处

每个链码都需要实现一下 Chaincode 接口

Chaincode接口

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

Init: 当链码实例化或者升级的时候,Init方法会被调用

Invoke 当链码收到调用(invoke)或者查询的时候,Invoke 会被调用

链码的基本结构

package main

// 引入相应的依赖包
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)

type SimpleChaincode struct {

}

// 链码实例化(instantiate)或 升级(upgrade)时调用 Init 方法
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response{

return shim.Success(nil)
}

// 链码收到调用(invoke) 或 查询 (query)时调用 Invoke 方法
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
return shim.Success(nil)
}

// 主函数 ,调用 shim.Start 方法
func main() {
err := shim.Start(new(SimpleChaincode))

if( err!= nil){
fmt.Printf("Error starting Simple Chaincode is %s \n",err)
}
}

链码通过 shim.ChaincodeStubInterface提供的方法来读取和修改账本状态。

helloworld

  • 初始化的时候,给 str 赋值 helloworld
  • 查询 str 当前的值
  • 重新设置 str 的值
  • 再次查询 str 的值
package main

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

type Helloworld struct {

}

func (t *Helloworld) Init(stub shim.ChaincodeStubInterface) peer.Response {

fmt.Println("helloworld init")
args := stub.GetStringArgs()
err := stub.PutState(args[0],[]byte(args[1]))

if err != nil {
shim.Error(fmt.Sprintf("helloworld init err %s",err))
}
return shim.Success(nil)
}

func (t *Helloworld) 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 {
shim.Error(err.Error())
}
return shim.Success([]byte(result))
}

func set (stub shim.ChaincodeStubInterface, args []string) (string,error){

fmt.Println("helloworld set")

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

func get(stub shim.ChaincodeStubInterface, args []string) (string,error){

value, err := stub.GetState(args[0])

if err != nil {
return "", fmt.Errorf("Failed to get asset: %s", args[0])
}
if value == nil {
return "", fmt.Errorf("Asset not found: %s", args[0])
}

return string(value),nil
}

func main() {
err := shim.Start(new(Helloworld))

if err != nil {
fmt.Printf("shim start err %s",err)
}
}

helloworld_test.go

package main

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

func checkInit(t *testing.T, stub *shim.MockStub, args [][]byte) {
res := stub.MockInit("1", args)
if res.Status != shim.OK {
fmt.Println("Init failed", string(res.Message))
t.FailNow()
}
}

func checkQuery(t *testing.T, stub *shim.MockStub, name string) {
res := stub.MockInvoke("1", [][]byte{[]byte("get"), []byte(name)})
if res.Status != shim.OK {
fmt.Println("Query", name, "failed", string(res.Message))
t.FailNow()
}
if res.Payload == nil {
fmt.Println("Query", name, "failed to get value")
t.FailNow()
}

fmt.Println("Query value", name, "was ", string(res.Payload))

}

func checkInvoke(t *testing.T, stub *shim.MockStub, args [][]byte) {
res := stub.MockInvoke("1", args)
if res.Status != shim.OK {
fmt.Println("Invoke", args, "failed", string(res.Message))
t.FailNow()
}
}

func Test_Helloworld(t *testing.T) {

hello := new(Helloworld)
stub := shim.NewMockStub("hello", hello)

checkInit(t, stub, [][]byte{[]byte("str"), []byte("helloworld")})
checkQuery(t, stub, "str")

checkInvoke(t, stub, [][]byte{[]byte("set"), []byte("str"), []byte("helloworld-1111")})
checkQuery(t, stub, "str")
}

通过 go test -v helloworld_test.go helloworld.go 测试相应的方法,运行结果:

=== RUN Test_Helloworld
helloworld init
Query value str was helloworld
helloworld set
Query value str was helloworld-1111
--- PASS: Test_Helloworld (0.00s)
PASS
ok command-line-arguments 0.028s

关注公众号

你可能感兴趣的:(Hyperledger,Fabric)