编写链码-helloworld

编写链码-helloworld

本地依赖安装(window, linux, mac都可以)

  • GOPATH可以包含多个路径: 第一个路径用来存放依赖包; 第二个路径设置为项目路径.

  • 国内使用go get命令获取依赖速度很慢, 可以使用gopm进行加速

    #安装到GOPATH/bin目录, 如果需要在命令行中直接使用,需将环境变量GOBIN设置为 GOPATH/bin, 并添加至环境变量中
    go get -u github.com/gpmgo/gopm
    
    #使用gopm 安装 fabric
    gopm get -g github.com/hyperledger/fabric
    
    #更多gopm命令使用, 参考: https://www.jianshu.com/p/a7c3aeb0948d
    

编写链代码

创建目录 helloworld, 并将目录路径添加至 GOPATH

  • helloworld.go

    package main
    
    import (
    	"github.com/hyperledger/fabric/core/chaincode/shim"
    	"github.com/hyperledger/fabric/protos/peer"
    	"log"
    )
    
    type HelloWorld struct {
    }
    
    func (this *HelloWorld) Init( stub shim.ChaincodeStubInterface) peer.Response {
    
    
    	args := stub.GetStringArgs()
    
    	err := stub.PutState(args[0], []byte(args[1]))
    	if err != nil {
    		shim.Error(err.Error())
    	}
    	return  shim.Success(nil)
    }
    
    
    func (this *HelloWorld)Invoke(stub shim.ChaincodeStubInterface) peer.Response  {
    
    	fn, args := stub.GetFunctionAndParameters()
    	if fn == "set"{
    		return this.set(stub, args)
    	}else if fn == "get"{
    		return this.get(stub, args)
    	}
    	return shim.Error("Invoke func error")
    }
    
    func (this *HelloWorld)set(stub shim.ChaincodeStubInterface,  args  []string)  peer.Response {
    	err := stub.PutState(args[0], []byte(args[1]))
    	if err != nil{
    		return shim.Error(err.Error())
    	}
    	return shim.Success(nil)
    }
    
    func (this *HelloWorld)get(stub shim.ChaincodeStubInterface, args []string) peer.Response  {
    
    	value, err := stub.GetState(args[0])
    	if err != nil{
    		return shim.Error(err.Error())
    	}
    	return shim.Success(value)
    }
    
    
    func main(){
    	err := shim.Start(new(HelloWorld))
    	if err != nil {
    		log.Println(err)
    		return
    	}
    }
    
  • 本地测试: helloworld_test.go

    package main
    
    import (
    	"testing"
    	"github.com/hyperledger/fabric/core/chaincode/shim"
    	"fmt"
    
    )
    
    
    
    
    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")
    }
    
    
  • 本地测试

    cd helloworld  
    go test -v  helloworld.go helloworld_test.go
    
    输出如下:
    === RUN   Test_Helloworld
    Query value str was  helloworld
    Query value str was  helloworld-1111
    --- PASS: Test_Helloworld (0.00s)
    PASS
    ok
    

部署链码

环境: Ubuntu 18.04

  • 将 helloworld 复制到 fabric-samples/chaincode目录下

  • 终端1–启动网络

    cd	chaincode-docker-devmode
    
    docker-compose -f docker-compose-simple.yaml up
    
    

    如果启动出错,删除所有的docker容器

    docker rm -f $(docker ps -aq)
    docker-compose -f docker-compose-simple.yaml down #停止网络

  • 终端2 --编译并启动链码

    #启动chaincode容器
    docker exec -it chaincode bash
    
    #进入链码目录
    cd helloworld
    
    #编译
    go build
    
    #启动链码
    CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./helloworld
    

    当peer:7051 启动链码时报错: ERRO 003 Received error from server, ending chaincode stream: rpc error: code = Unimplemented desc = unknown service protos.ChaincodeSupport

    是因为版本问题, 解决方法:

    https://stackoverflow.com/questions/48007519/unimplemented-desc-unknown-service-protos-chaincodesupport

  • 终端 3 – 操作链码

    #启动cli容器
    docker exec -it cli bash
    
    #安装链码
    peer chaincode install -p chaincodedev/chaincode/helloworld -n mycc -v 0
    
    #实例化链码
    peer chaincode instantiate -n mycc -v 0 -c '{"Args":["str","helloworld"]}' -C myc
    
    #查询链码
    peer chaincode query -n mycc -c '{"Args":["get","str"]}' -C myc 
    
    #调用链码中的set方法
    peer chaincode invoke -n mycc -c '{"Args":["set", "str", "helloworld youngqq"]}' -C myc
    
    #查询链码
    peer chaincode query -n mycc -c '{"Args":["get","str"]}' -C myc 
    
    

代码分析

//fabric/core/chaincode/shim/interfaces.go

// Chaincode interface must be implemented by all chaincodes. The fabric runs
// the transactions by calling these functions as specified.
type Chaincode interface {
	// Init is called during Instantiate transaction after the chaincode container
	// has been established for the first time, allowing the chaincode to
	// initialize its internal data
	Init(stub ChaincodeStubInterface) pb.Response

	// Invoke is called to update or query the ledger in a proposal transaction.
	// Updated state variables are not committed to the ledger until the
	// transaction is committed.
	Invoke(stub ChaincodeStubInterface) pb.Response
}
  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值