快速编写和运行一个Chaincode
创建和安装链码
编写一个简单的链码文件
//包名
//一个chaincode通常是一个golang源码文件,这个包名必须是main
package main
//导入包
//chaincode需要引入一些Fabric提供的系统包,这些系统包提供了chaincode和Fabirc进行通信的接口。
import (
"fmt"
//"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
//定义chaincode主结构体
//每个chaincode都需要定义个结构体,结构体的名字可以是任意符合golang命名规范的字符串。chaincode的住结构体必须实现Chaincode接口
// type Chaincode interface {
// Init(stub ChaincodeStubInterface) pb.Response
// Invoke(stub ChaincodeStubInterface) pb.Response
// }
type SimpleChaincode struct {
}
//Init方法
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
return shim.Success(nil)
}
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
return t.invoke(stub, args)
}
return shim.Error("Inva9n name. Expecting \"invoke\"")
}
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
return shim.Success(nil)
}
//main函数
//调用shim包的Start方法,启动chaincode,如果启动成功,这个函数会一直阻塞在这个地方,不会退出。
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
部署链码文件
# 查看当前的peer节点加入了哪些channel
root@e0729782fd02:/# peer channel list
2019-11-19 06:51:58.735 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined:
mychannel
# 部署/安装链码
root@e0729782fd02:/opt/gopath/src# peer chaincode install -n mychaincode -v 1.1 -p github.com/chaincode_example
2019-11-19 06:57:35.614 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-19 06:57:35.614 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-11-19 06:57:37.495 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
# 实例化
root@e0729782fd02:/opt/gopath/src# peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mychaincode -v 1.1 -c '{"Args":["init","a","100","b","200"]}'
2019-11-19 07:03:51.485 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-19 07:03:51.486 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
# 调用
root@e0729782fd02:/opt/gopath/src# peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mychaincode -c '{"Args":["invoke","1","a","b"]}'
2019-11-19 07:05:40.351 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
如何通过Chaincode进行交易背书
当一个节点接收到一个交易的时候,会调用VSCC(系统Chaincode,专门负责背书操作)与交易的Chaincode共同来验证交易的合法性。VSCC和Chaincode通常会做以下的校验:
- 所有背书是否有效(参与背书的签名是否有效)
- 参与背书的数量是否满足要求
- 所有背书参与方是否满足要求
背书政策(Policy)是指定第二和第三点的一种方式,比如下面的一个示例-P
:
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mychaincode -v 1.1 -c
'{"Args:["init","a","100","b","200"]"}' -P "AND('Org1MSP.member','Org2MSP.member')"
上述命令使用AND
表示组织编号为Org1MSP和Org2MSP的组织中的任何一个用户共同参与背书。另外背书规则还可以采用OR
或者两者都用,比如:
"OR(''Org1MSP.member,AND("Org2MSP.member","Org3MSP.member"))"
背书规则指针对写入操作,对查询操作不需要背书。
容器外调试Chaincode方法
-
首先,注册需要调试的chaicode。
如果需要在docker外运行chaincode,需要向Fabric提交Chaincode的名字和版本号,其实际注册的chaincode代码并不重要。注册步骤如下:- 修改peer节点的启动模式:通过环境变量设置CORE_CHAINCODE_MODE=net
- 注册Chaincode:
peer chaincode install
和peer chaincode instantiate
命令。
-
将Peer节点设置为调试模式。
也就是设置CORE_CHAINCODE_MODE=dev,设置了dev后,当前Peer不能执行peer chaincode instantiate
。 -
编译并运行chaincode
通过go build
命令编译go文件。
运行chaincode需要设置响应的环境变量和系统参数:CORE_PEER_ADDRESS
:peer节点地址,如192.168.0.1:7051CORE_CHAINCODE_ID_NAME
:chaincode的名字和版本号,比如:mychaincode:1.0- log等级:例如
CORE_CHAINCODE_LOGGING_LEVEL=debug
和CORE_CHAINCODE_LOGGING_SHIM=debug
。
然后通过
./<go文件名字> -peer/address=192.168.0.1:7052
执行。 -
调用chaincode
通过invoke
方法调用。