Hyperledger Fabric测试不同组织链码调用
在熟悉fabric的各种操作之后,开始针对多组织智能合约的应用,发现不同组织的链码应该不同,这时候相互调用涉及到一个链码如何部署的问题。
本测试环境,fabric1.1版本,两个组织A和B,其中A安装官方链码go/src/github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
B安装我自己写的链码,链码里调用官方链码的交易以及查询功能,链码如下:
//为了操作更简便,我把调用的参数写的跟A组织传入一样,后面操作只要修改链码名称就可以了,invoke和query均相同。
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("ChaincodeInvoke Init")
return shim.Success(nil)
}
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
fmt.Println("ChaincodeInvoke Invoke")
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
//调用A链码的invoke
return t.invoke(stub, args)
} else if function == "query" {
//调用A链码的query
return t.query(stub, args)
}
return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A, B string // Entities
if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
A = args[0]
B = args[1]
parm1:=[]string{"invoke",A,B,args[2]}
queryArgs:=make([][]byte,len(parm1))
for i,arg:=range parm1{
queryArgs[i]=[]byte(arg)
}
response:=stub.InvokeChaincode("mychannel",queryArgs,"mychannel")
if response.Status !=shim.OK{
return shim.Error("failed to invoke other chaincode")
}
result:=string(response.Payload)
return shim.Success([]byte("success to invoke:"+result)) //和官方输出有点区别,我这里输出多了个“success to invoke",便于区分
}
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
account:=args[0]
parm1:=[]string{"query",account}
queryArgs:=make([][]byte,len(parm1))
for i,arg:=range parm1{
queryArgs[i]=[]byte(arg)
}
response:=stub.InvokeChaincode("mychannel",queryArgs,"mychannel")
if response.Status !=shim.OK{
return shim.Error("failed to invoke other chaincode")
}
result:=string(response.Payload)
return shim.Success([]byte("success to invoke:"+result))
}
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
想到这个问题的,环境肯定都没啥问题,这里直接说结果。
A组织安装example链码,实例化
peer chaincode install -n mychannel -p github.com/hyperledger/fabric/aberic/chaincode/go/chaincode_example02 -v 1.0
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mychannel -c '{"Args":["init","A","100","B","100"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" -v 1.0
peer chaincode query -C mychannel -n mychannel -c '{"Args":["query","A"]}'
peer chaincode invoke -C mychannel -n mychannel -c '{"Args":["invoke","A","B","5"]}'
//官方链码很简单,实例化的时候,A,B两个账户存100快,然后invoke是AB之间转账,这里是A给B转账5块钱。
转完之后A 95,B 105.
peer channel list //列出当前通道
peer chaincode list --installed //列出当前组织安装的链码
peer chaincode list --instantiated -C mychannel //列出通道已经实例化的链码
切换到另外个组织B,我这里嫌麻烦用的是单机,执行的是cli客户端操作,修改一下cli容器的环境变量就可以。
peer channel join -b mychannel.block //加入创建的通道
peer chaincode install -n test -p github.com/hyperledger/fabric/aberic/chaincode/go/test -v 1.0
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n test -c '{"Args":[]}' -P "OR ('Org1MSP.member','Org2MSP.member')" -v 1.0
peer chaincode query -C mychannel -n test -c '{"Args":["query","A"]}'//操作失败,显示找不到链码
peer chaincode invoke -C mychannel -n test -c '{"Args":["invoke","A","B","10"]}'
peer chaincode list --installed //列出B组织安装的链码,可以看到只有B组织test链码
peer chaincode list --instantiated -C mychannel //这里可以看到mychannel通道里实例化链码包括A组织的和B组织的
原因:虽然都在同一个通道,但是AB组织都只有各自的链码,即使B组织链码调用了A链码,但是B组织没有安装链码,无法执行A链码的逻辑。
修改
在B组织安装A的链码,B的链码就可以调用了,同时由于B安装A的链码,所以在B组织执行A链码也是ok的,
感觉这里相当于把A的链码当成一个函数传入了。安装A链码,就相当于引入了这个库,要不然找不到。
//B安装A的链码不需要实例化,同一个通道的某个链码只需要实例化一次。
peer chaincode list --installed //列出B组织安装的链码,可以看到AB链码均存在了。
peer chaincode query -C mychannel -n test -c '{"Args":["query","A"]}'//成功,和A组织执行查询结果相同
peer chaincode invoke -C mychannel -n test -c '{"Args":["invoke","A","B","10"]}'//成功,和A组织执行交易结果相同
------
ps:多加一句,回到A组织,查询安装的链码只有官方链码,所以A还是智能查询A自己的链码。
图都都没贴,但是核心链码和步骤都写了,记住结论,如果一个组织要调用其他链码,那么当前组织一定要安装调用的链码