Fabric: Using InvokeChaincode to achieve cross-channel data access

Because I encountered some problems at work, I considered using Fabric’s cross-channel chain code calling method InvokeChaincode() to solve them. This article mainly records the following usage process of InvokeChaincode() and the problems encountered in the Fabric test network.

1 Preparation

1.1 Understanding InvokeChaincode

The function of InvokeChaincode is to call the specified chain code. When the called chaincode and the chaincode executing InvokeChaincode are or are not on the same channel, they can play different roles. The specific rules are as follows:

  • If on the same channel as the called chaincode, it simply adds the calling chaincode’s read set and write set to the calling transaction.
  • If on a different channel than the called chaincode, only the response is returned to the calling chaincode; any putState() calls from the called chaincode will have no impact on the ledger(My understanding is that in this case, data can only be read but not written).

In addition, the parameters and return values of InvokeChaincode are as follows:

  • Parameter chaincodeName: string type, target chaincode name.
  • Parameter args: [][]byte type, parameter list.
  • Parameter channel: string type, the name of the channel where the target chain code is located. If the channel value is “”, it indicates the current channel.
  • Return value peer.Response: The peer.Pesponse type data is the response result to the peer node operation. By processing the peer.Response type data, you can obtain the status, events and returned values of the operation execution. In other words, the return value of the target chain code can be extracted from peer.Response. peer.Response data usually contains the following fields:
Field name Meaning
Status The status code of the operation, if the operation is successful, it is 200
Payload The return result of the operation, its type is: []byte
Message The error message of the operation, only Valid on error
TxId Transaction ID where the operation is located
Proposal The proposal where the operation is located
1.2 Preparation

In order to reduce the tedious work of creating nodes, channels, etc., we will make full use of the test network test-network in Fabric. Before realizing cross-channel data access, the basic environment needs to be set up first. Specifically include the following:

  • Use the ./network.sh up command to create the peer node, Orderer node and cli client.
  • Use the ./network.sh createChannel -c command to create two channels channel1 and channel2. These two channels will share all peers and Orderers. node.
  • Configure the peer CLI and bind the peer CLI to the peer0 node on Org1.
  • Deploy the go language chaincode sample provided in fabric-samples to channel1, and use peer chaincode invoke to call the chaincode’s The InitLedger method writes data to the world state of the chaincode. The specific code is as follows:
#Deploy the chaincode in asset-transfer-basic/chaincode-go to channel1
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go -c channel1
#Execute InitLedger()
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${<!-- -->PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example. com/msp/tlscacerts/tlsca.example.com-cert.pem" -C channel1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${<!-- -->PWD}/organizations/peerOrganizations/ org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${<!-- -->PWD}/organizations/peerOrganizations/ org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"TransferAsset","Args":["asset6 ","Christopher"]}'
#Query all data in world state
peer chaincode query -C channel1 -n basic -c '{"Args":["GetAllAssets"]}'

Tips: The above work is not the focus of this article. You can refer to other materials for the specific process, so I will not go into details here.

After the above preparations are completed, you need to write a new chaincode file to specifically reference the InvokeChaincode method, and deploy the new chaincode to the channel channel2.

2 Implementation

Create a chaincode directory sherryChaincode in the test-network directory, and create a chaincode file mychaincode.go in this directory. The code is as follows:

/*
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"log"
)

type TestSmartContract struct {<!-- -->
contractapi.Contract
}

func (s *TestSmartContract) QueryData(ctx contractapi.TransactionContextInterface,chaincode_name string,channel_name string,channel_args []string) (string, error) {<!-- -->
chaincodeName := chaincode_name
channelName := channel_name
chaincodeArgs := make([][]byte, len(channel_args))
for i,item := range channel_args {<!-- -->
chaincodeArgs[i]=[]byte(item)
}
\t
response := ctx.GetStub().InvokeChaincode(chaincodeName, chaincodeArgs, channelName)
data := response.Payload
return string(data), nil
}c
func main() {<!-- -->
assetChaincode, err := contractapi.NewChaincode( & amp;TestSmartContract{<!-- -->})
if err != nil {<!-- -->
log.Panicf("Error creating asset-transfer-basic chaincode: %v", err)
}
if err := assetChaincode.Start(); err != nil {<!-- -->
log.Panicf("Error starting asset-transfer-basic chaincode: %v", err)
}
}

Then deploy the chaincode to the channel2 channel, as follows:

#Jump to the test-network directory first
sudo ./network.sh deployCC -ccn basic_test -ccp ./sherryChaincode -ccl go -c channel2

Tips: Pay attention to the directory in the cc parameter and locate the path where the go.mod file is located.
Then use the peer chaincode query command to verify the execution of InvokeChaincode.
Example 1

peer chaincode query -C channel2 -n basic_test -c '{"Args":["QueryData","basic","channel1","["GetAllAssets ]"]}'

Its implementation is as follows:

Example 2

peer chaincode query -C channel2 -n basic_test -c '{"Args":["QueryData","basic","channel1","["ReadAsset ","asset6"]"]}'

The code execution results are as follows:

At this point, cross-channel access to data is achieved.

2.2 Supplementary instructions

While writing the mychaincode.go file, I encountered some error messages. It is organized as follows:

  • If an error occurs when deploying the chain code using the deployCC command, it is usually a syntax error in the Go language. Here you can simply modify the code according to the prompt information.
  • Even if the deployCC command succeeds, it does not mean that the chain code can run successfully. Subsequent chain code compilation and execution error information can be viewed through the channel command docker. First run the docker ps -a command. If the following situation occurs, it means that the chain code is still wrong.

    In this case, you can view the specific error information through the docker log. The command is as follows:
docker logs --details <CONTAINER-ID>

After the code is modified, it needs to be deployed again using deployCC.

  • When starting the mychaincode.go file with only one method named queryData, I encountered this error: Contracts are required to have at least 1 (none-ignored ) public method.
    Reason for the error: If the first letter of the method name in the Go language is lowercase, it means that other packages cannot use this method, that is, it is private. In the Go language, there must be a public method. So for this error, just capitalize the first letter of the method name, i.e. QueryData.
  • The return value type of the InvokeChaincode method is peer.Response. If QueryData directly returns peer.Response, for example, as follows Writing method:
func (s *TestSmartContract) QueryData(ctx contractapi.TransactionContextInterface) peer.Response {<!-- -->
chaincodeName := "basic"
channelName := "channel1"
chaincodeArgs := make([][]byte,1)
chaincodeArgs[0]=[]byte("GetAllAssets")

response := ctx.GetStub().InvokeChaincode(chaincodeName, chaincodeArgs, channelName)
return response
}

This way of writing will prompt an error: Cannot use metadata. Metadata did not match schema. In order to solve this error, the return value type of QueryData was changed to (string,error) in the final code.

  • In the QueryData method, the parameter channel_args is used to receive the method and its parameters to be executed in the called chain code, so the channel_args parameter here should receive The data type is slice. However, ...string cannot be used here but []string must be used to specify parameters for channel_args. At the same time, pay attention to the writing method of the slice part of the parameter in peer chaincode query.

Reference materials

  1. https://blog.csdn.net/weixin_41946008/article/details/123044664
  2. https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html