Fabric 1.0链码间调用方法咨询及相关问题求解(需示例)
Hey folks! Let's dive into how to implement chaincode-to-chaincode calls in Hyperledger Fabric 1.0, tackle your specific questions, and share working example code to make this concrete.
Core Concept: How Chaincode Calls Work
In Fabric 1.0, a chaincode can invoke another chaincode using the InvokeChaincode method from the ChaincodeStubInterface. This method lets you trigger functions in a target chaincode—either on the same channel (the most common use case) or across channels (which requires extra configuration). All state changes from both chaincodes are committed atomically as part of the same transaction.
Your Questions, Answered
Q1: Can two chaincodes be installed on a single peer?
Absolutely! There's no restriction on running multiple chaincodes on a single peer. You just need to install each chaincode separately with unique names/versions to avoid conflicts, then instantiate them on your target channel(s). For example:
# Install first chaincode peer chaincode install -n assettransfer -v 1.0 -p github.com/assettransfer # Install second chaincode peer chaincode install -n auditlog -v 1.0 -p github.com/auditlog
Q2: How to invoke each other if two chaincodes are installed on different peers?
Great question. Here's what you need to know:
- Both chaincodes must be instantiated on the same channel—chaincode calls rely on shared channel state, so cross-channel calls are a separate, more complex scenario.
- The endorsing peer(s) handling the transaction must have the target chaincode installed. If your calling chaincode is on Peer A and the target is on Peer B, Peer A needs to have the target chaincode installed too (since it will act as an endorser for the cross-chaincode call). Alternatively, you can route the invocation to a peer that has both chaincodes installed.
- Ensure your channel's policy allows chaincode-to-chaincode calls (the default policy usually permits this, but double-check if you've customized policies).
Example Code: Cross-Chaincode Invocation
Let's build two simple chaincodes: AssetTransfer (manages asset ownership) and AuditLog (records asset transfers). The AssetTransfer chaincode will call AuditLog every time an asset is transferred.
1. Target Chaincode: AuditLog
This chaincode exposes a recordTransfer function to log asset movements:
package main import ( "fmt" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" ) type AuditLogChaincode struct{} func (t *AuditLogChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { // No initialization needed here return shim.Success(nil) } func (t *AuditLogChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { function, args := stub.GetFunctionAndParameters() switch function { case "recordTransfer": return t.recordTransfer(stub, args) default: return shim.Error("Invalid function name. Supported: recordTransfer") } } func (t *AuditLogChaincode) recordTransfer(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 3 { return shim.Error("Incorrect args: expect [assetID, from, to]") } assetID, from, to := args[0], args[1], args[2] timestamp := stub.GetTxTimestamp().String() logEntry := fmt.Sprintf("Transfer: Asset %s moved from %s to %s at %s", assetID, from, to, timestamp) // Save log entry to ledger err := stub.PutState(assetID+"_log", []byte(logEntry)) if err != nil { return shim.Error(fmt.Sprintf("Failed to save log: %v", err)) } return shim.Success([]byte(logEntry)) } func main() { if err := shim.Start(new(AuditLogChaincode)); err != nil { fmt.Printf("Error starting AuditLog chaincode: %v", err) } }
2. Calling Chaincode: AssetTransfer
This chaincode updates asset ownership and calls AuditLog to record the transfer:
package main import ( "fmt" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" ) type AssetTransferChaincode struct{} func (t *AssetTransferChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { return shim.Success(nil) } func (t *AssetTransferChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { function, args := stub.GetFunctionAndParameters() switch function { case "transferAsset": return t.transferAsset(stub, args) default: return shim.Error("Invalid function name. Supported: transferAsset") } } func (t *AssetTransferChaincode) transferAsset(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 3 { return shim.Error("Incorrect args: expect [assetID, from, to]") } assetID, from, to := args[0], args[1], args[2] // Update asset owner in this chaincode's state err := stub.PutState(assetID, []byte(to)) if err != nil { return shim.Error(fmt.Sprintf("Failed to update asset owner: %v", err)) } // Call AuditLog chaincode (same channel, so empty string for channel name) invokeResp := stub.InvokeChaincode( "auditlog", // Target chaincode name [][]byte{[]byte("recordTransfer"), []byte(assetID), []byte(from), []byte(to)}, // Arguments "" // Channel name (empty = same channel) ) if invokeResp.Status != shim.OK { return shim.Error(fmt.Sprintf("Failed to call AuditLog: %s", invokeResp.Message)) } // Return combined success message successMsg := fmt.Sprintf( "Asset %s transferred from %s to %s. Log entry: %s", assetID, from, to, string(invokeResp.Payload), ) return shim.Success([]byte(successMsg)) } func main() { if err := shim.Start(new(AssetTransferChaincode)); err != nil { fmt.Printf("Error starting AssetTransfer chaincode: %v", err) } }
3. Deployment & Test Steps
- Install both chaincodes on your peer(s):
peer chaincode install -n assettransfer -v 1.0 -p github.com/assettransfer peer chaincode install -n auditlog -v 1.0 -p github.com/auditlog - Instantiate both on the same channel (e.g.,
mychannel):peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n assettransfer -v 1.0 -c '{"Args":[]}' -P "AND ('Org1MSP.peer')" peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n auditlog -v 1.0 -c '{"Args":[]}' -P "AND ('Org1MSP.peer')" - Invoke the transfer function:
peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n assettransfer -c '{"Args":["transferAsset","asset1","Alice","Bob"]}' - Query the audit log to verify:
peer chaincode query -C mychannel -n auditlog -c '{"Args":["query","asset1_log"]}'
内容的提问来源于stack exchange,提问作者Tejal tandale

