文/谦益
1、在GOPATH
目录下git源码
在 GOPATH
目录下,下载源码:
git clone http://gerrit.hyperledger.org/r/fabric
git clone http://gerrit.hyperledger.org/r/fabric-ca
我们写链码需要用到里面的包。
2、新建一个go文件
- 随便建一个目录,反正不在本地调试,建议是在
GOPATH
目录下面新建 - 再新建一个go文件,写入代码:
package main
import (
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
type LGSimpleChaincode struct {
}
func (t *LGSimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("LGSimpleChaincode -> Init")
_, args := stub.GetFunctionAndParameters()
var A, B string
var Aval, Bval int
var err error
if len(args) != 4 {
return shim.Error("参数数量不对")
}
A = args[0]
Aval, err = strconv.Atoi(args[1])
if err != nil {
return shim.Error("参数值类型不对")
}
B = args[2]
Bval, err = strconv.Atoi(args[3])
if err != nil {
return shim.Error("参数值类型不对")
}
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
func (t *LGSimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("LGSimpleChaincode -> Invoke")
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
return t.invoke(stub, args)
} else if function == "delete" {
return t.delete(stub, args)
} else if function == "query" {
return t.query(stub, args)
}
return shim.Error("方法名不对,只支持 invoke,delete,query")
}
//交易转账
func (t *LGSimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A, B string
var Aval, Bval int
var X int
var err error
if len(args) != 3 {
return shim.Error("参数数量不对")
}
A = args[0]
B = args[1]
Avalbytes, err := stub.GetState(A)
if err != nil {
return shim.Error("没找到第一个的用户金额")
}
if Avalbytes == nil {
return shim.Error("第一个用户金额为nil")
}
Aval, _ = strconv.Atoi(string(Avalbytes))
Bvalbytes, err := stub.GetState(B)
if err != nil {
return shim.Error("没找到第二个的用户金额")
}
if Bvalbytes == nil {
return shim.Error("第二个用户金额为nil")
}
Bval, _ = strconv.Atoi(string(Bvalbytes))
X, err = strconv.Atoi(args[2])
if err != nil {
return shim.Error("转账金额异常")
}
Aval = Aval - X
Bval = Bval + X
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
//重新更新用户金额
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil)
}
func (t *LGSimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) != 1 {
return shim.Error("参数异常")
}
A := args[0]
err := stub.DelState(A)
if err != nil {
return shim.Error("删除用户异常")
}
return shim.Success(nil)
}
func (t *LGSimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A string
var err error
if len(args) != 1 {
return shim.Error("查询参数异常")
}
A = args[0]
Avalbytes, err := stub.GetState(A)
if err != nil {
jsonResp := "{\"Error\":\"用户金额查询异常 " + A + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
jsonResp := "{\"Error\":\"用户金额为nil " + A + "\"}"
return shim.Error(jsonResp)
}
jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
fmt.Printf("Query Response:%s\n", jsonResp)
return shim.Success(Avalbytes)
}
func main() {
err := shim.Start(new(LGSimpleChaincode))
if err != nil {
fmt.Printf("链码部署失败: %s", err)
}
}
3、拷贝链码到docker容器里面
- 这里要注意一点是,链码必须是放在容器的
/opt/gopath/src
目录下,也就是GOPATH
目录下 - 这里使用
docker cp
命令,从本地拷贝到容器中,3316a70035e8
是我的容器id,这个你得要看你起的服务里面容器id是多少docker cp ./hello/hello.go 3316a70035e8:/opt/gopath/src/github.com/chaincode/lyg/
怎么查看你容器的id,执行
docker ps -a
找到 名字为 cli
的容器
其实 docker cp
也可以直接使用容器的名字进行拷贝:
docker cp ./hello/hello.go cli:/opt/gopath/src/github.com/chaincode/lyg/
4、安装链码
这里我启动的服务是官方的 first-network
网络,怎么启动,怎么搭建环境,可以查看我的另一篇文章:
实战-fabric 环境搭建,创建我们的第一条网络
- 进入到docker容器
docker exec -it cli bash
- 开始安装链码
peer chaincode install -n lghello -v 1.0 -p github.com/chaincode/lyg/
解释下参数说明:
-n
链码名字-v
版本-p
链码目录,定位到链码目录下面
5、实例化链码
peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n lghello -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P 'OR ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')'
解释下参数说明:
-n
链码名字-v
版本-p
链码目录,定位到链码目录下面--tls
是否启用tls证书--cafile
如果启用tls证书,这参数是ca的地址-P
这是背书 方案,背书可以理解是执行链码成功的策略,要那几个节点同意后,链码就执行生效-o
排序节点,要指定到端口-C
初始化参数
实例化完成后,会再docker里面创建一个容器,可以通过
docker ps -a
查看
6、调用链码
- 查询
peer chaincode query -C mychannel -n lghello -c '{"Args":["query","a"]}'
- 转账
peer chaincode invoke -C mychannel -n lghello -c '{"Args":["invoke","a","b","10"]}' -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
这里要注意,转账需要传对应的排序节点和tls证书
觉得内容不错可以关注我的慕课账号【谦益】,我会继续更新
[获取授权]
热门评论
推荐两个fabric开发教程:
Fabric区块链Java开发详解
Fabric区块链NodeJs开发详解