Hyperledger Fabric跨组织链码调用实现及测试场景问询
跨组织链码调用与数据计算实现方案
针对你描述的场景——ORG1的chaincode1存储用户信息,ORG2的chaincode2被chaincode1调用、从chaincode1获取数据并完成计算——我会分实现步骤和测试方案两部分来拆解,都是基于Hyperledger Fabric的标准流程:
一、实现步骤
1. 确保跨组织网络基础配置就绪
首先得保证ORG1和ORG2已经在同一个通道(或双方都加入的多通道)中,且彼此的MSP(成员服务提供者)已经被通道配置认可。如果还没完成这一步,需要先通过configtxlator更新通道配置,将ORG2的MSP信息加入通道的组织列表,让两个组织的节点能在通道内互通。
2. 配置链码访问控制与背书策略
链码间的调用和数据访问需要对应的权限支撑:
- ACL配置:默认情况下,同通道内的链码允许互相调用和访问状态,但如果你的网络有严格权限要求,需要修改通道的
configtx.yaml中的ACL规则,比如将chaincode-to-chaincode权限设置为OR('Org1MSP.member','Org2MSP.member'),确保两个组织的链码能互相调用;同时保证chaincode-to-state权限允许chaincode2访问chaincode1的账本数据。 - 背书策略:在实例化chaincode2时,要设置符合业务需求的背书策略。比如如果要求计算操作必须由ORG2的节点背书,策略可以设为
AND('Org2MSP.peer');如果允许ORG1或ORG2的节点背书,就设为OR('Org1MSP.peer','Org2MSP.peer')。注意:chaincode1调用chaincode2时,需要满足chaincode2的背书策略才能完成交易。
3. 编写chaincode2的核心逻辑
chaincode2需要实现两个核心能力:接收chaincode1传入的参数,以及调用chaincode1获取用户数据进行计算。以Go语言链码为例:
// chaincode2的Compute函数,接收chaincode1传入的用户ID和计算参数 func (s *SmartContract) Compute(ctx contractapi.TransactionContextInterface) error { // 获取chaincode1传入的参数:用户ID、计算参数 args := ctx.GetStub().GetArgs() userId := string(args[1]) computeParam := string(args[2]) // 调用chaincode1获取用户数据,第一个参数是chaincode1的部署名称,第三个参数是通道名(同通道传空) userDataBytes, err := ctx.GetStub().InvokeChaincode("chaincode1", []string{"GetUser", userId}, "") if err != nil { return fmt.Errorf("调用chaincode1失败: %v", err) } // 解析用户数据并执行计算逻辑 var userData map[string]interface{} err = json.Unmarshal(userDataBytes, &userData) if err != nil { return fmt.Errorf("解析用户数据失败: %v", err) } // 这里写你的计算逻辑,比如根据userData和computeParam计算结果 computeResult := fmt.Sprintf("计算结果:%v * %v", userData["score"], computeParam) // 可选:将计算结果存入账本(如果需要持久化) err = ctx.GetStub().PutState(fmt.Sprintf("result_%s", userId), []byte(computeResult)) if err != nil { return fmt.Errorf("存储计算结果失败: %v", err) } // 返回计算结果给chaincode1 ctx.GetStub().SetReturnValue([]byte(computeResult)) return nil }
4. 编写chaincode1的调用逻辑
在chaincode1中添加触发调用chaincode2的函数,比如:
// chaincode1的TriggerCompute函数,触发chaincode2的计算 func (s *SmartContract) TriggerCompute(ctx contractapi.TransactionContextInterface) error { // 收集计算所需的特定信息:比如用户ID、计算参数 args := ctx.GetStub().GetArgs() userId := string(args[1]) computeParam := string(args[2]) // 调用chaincode2的Compute函数 resultBytes, err := ctx.GetStub().InvokeChaincode("chaincode2", []string{"Compute", userId, computeParam}, "") if err != nil { return fmt.Errorf("调用chaincode2失败: %v", err) } // 可选:处理chaincode2返回的结果,比如存入chaincode1的账本 err = ctx.GetStub().PutState(fmt.Sprintf("compute_result_%s", userId), resultBytes) if err != nil { return fmt.Errorf("存储计算结果失败: %v", err) } return nil }
5. 部署与实例化chaincode2
- 在ORG2的peer节点上安装chaincode2:
peer lifecycle chaincode install chaincode2.tar.gz - 批准chaincode2的定义(ORG2的管理员操作):
peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --channelID mychannel --name chaincode2 --version 1.0 --sequence 1 --waitForEvent - 因为chaincode1在ORG1,需要ORG1也批准chaincode2的定义(如果背书策略包含ORG1),然后提交chaincode2到通道:
peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID mychannel --name chaincode2 --version 1.0 --sequence 1 --peerAddresses peer0.org1.example.com:7051 --peerAddresses peer0.org2.example.com:7051
二、测试方案
测试需要从单元层到集成层逐步验证,确保整个流程的正确性:
1. 单元测试(本地开发阶段)
使用Fabric的链码测试框架,模拟链码间的调用:
- 对于chaincode2,模拟调用chaincode1的
GetUser函数返回模拟数据,验证计算逻辑是否正确; - 对于chaincode1,模拟调用chaincode2的
Compute函数,验证参数传递和结果处理是否正常; - 以Go为例,用
testing包编写测试用例,使用mockstub来模拟链码的执行环境。
2. 集成测试(测试网络环境)
基于Fabric的test-network搭建包含ORG1和ORG2的测试网络:
- 部署chaincode1到ORG1的peer,部署chaincode2到ORG2的peer,完成通道实例化;
- 通过CLI调用chaincode1的
TriggerCompute函数,传入测试用户ID和计算参数; - 查询chaincode1或chaincode2的账本,验证计算结果是否正确存储;
- 检查交易的背书情况,确认符合预设的背书策略。
3. 跨组织节点验证
- 在ORG1的peer节点发起调用,验证交易能被ORG2的peer正确背书(如果背书策略要求);
- 在ORG2的peer节点查询账本,确认计算结果已经同步到ORG2的节点;
- 模拟ORG2的peer节点故障,验证chaincode1调用chaincode2时是否能正常容错(如果有多个ORG2的peer)。
内容的提问来源于stack exchange,提问作者Kshitiz Sharma
相关产品推荐
相关产品推荐

