External Chaincode Launcher — Hyperledger Fabric

Hyperledger Fabric v2.0 came with many features and “External Chaincode Launcher” is one of them. Prior to fabric v2.0, peer node used a specific language like golang to generate a chaincode container image from the chaincode source code. Prior releases of Fabric required peers to have access to a Docker daemon in order to build and launch chaincode — something that may not be desirable in production environments due to the privileges required by the peer process.

Traditionally, chaincodes are launched by the peer, and then connect back to the peer. It is now possible to run chaincode as an external service, for example in a Kubernetes pod, which a peer can connect to and utilize for chaincode execution.

In this tutorial, we will try and run a chaincode as an external service.

Prerequisites

  • Hyperledger Fabric v2.2.3 ( tutorial )

Step 1: Setting up the external builder and launcher

External Builders and Launchers is an advanced feature that typically requires custom packaging of the peer image so that it contains all the tools your builder and launcher require.

Open the config/core.yaml file at the top of the fabric-samples hierarchy.

Modify the field externalBuilders as the following:

externalBuilders:
- path: /opt/gopath/src/github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external/sampleBuilder
name: external-sample-builder

This configuration sets the name of the external builder as external-sample-builder, and the path of the builder to the scripts provided in this sample. Note that this is the path within the peer container, not your local machine.

To set the path within the peer container, you will need to modify the container compose file to mount a couple of additional volumes. Open the file test-network/docker/docker-compose-test-net.yaml, and add to the volumes section of both peer0.org1.example.com and peer0.org2.example.com the following two lines:

- ../..:/opt/gopath/src/github.com/hyperledger/fabric-samples
- ../../config/core.yaml:/etc/hyperledger/fabric/core.yaml

This will mount the fabric-sample builder into the peer container so that it can be found at the location specified in the config file, and override the peer’s core.yaml config file within the fabric-peer image so that the config file modified above is used.

Step 2: Packaging and installing Chaincode

chaincode.env file has two environment variables CHAINCODE_SERVER_ADDRESS and CHAINCODE_ID which are passed to the Asset-Transfer-Basic chaincode.

Have a look at the main function of the chaincode:

connection.json configuration file is required by the peer so that it can connect to the external chaincode service.

The address specified in the connection.json must correspond to the CHAINCODE_SERVER_ADDRESS value in chaincode.env, which is asset-transfer-basic.org1.example.com:9999 in our example.

Because we will run our chaincode as an external service, the chaincode itself does not need to be included in the chaincode package that gets installed to each peer. Only the configuration and metadata information needs to be included in the package.

First, create a code.tar.gz archive containing the connection.json file:

Then, create the chaincode package, including the code.tar.gz file and the supplied metadata.json file:

Step 3: Bring up the Network

We will use the test-network which comes with the Fabric installation.

./network.sh up createChannel -c mychannel -ca

This will start the network with 2 Orgs and 1 peer per org and create a default channel “mychannel”.

Step 4: Installing the external chaincode

cd fabric-samples/test-network . ./scripts/envVar.sh export FABRIC_CFG_PATH=../config setGlobals 1 ../bin/peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz setGlobals 2 ../bin/peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz

The output will be a chaincode pakage identifier, which will be required in the further steps.

If needed, you can query the installed chaincode to get its package-id:

setGlobals 1 ../bin/peer lifecycle chaincode queryinstalled

Edit the chaincode.env file in the fabric-samples/asset-transfer-basic/chaincode-external directory as necessary to set the CHAINCODE_ID variable to the chaincode package-id obtained above.

Step 5: Running the External Chaincode Service

To run the service in a container, from a different terminal, build an Asset-Transfer-Basic docker image, using the supplied Dockerfile, using the following command in the fabric-samples/asset-transfer-basic/chaincode-external directory:

docker build -t hyperledger/asset-transfer-basic .

Then, start the Asset-Transfer-Basic service:

docker run -d -it --rm --name asset-transfer-basic.org1.example.com --hostname asset-transfer-basic.org1.example.com --env-file chaincode.env --network=net_test hyperledger/asset-transfer-basic

This will start the container and start the external chaincode service within it.

Step 6: Chaincode Approval and Commit

setGlobals 2 ../bin/peer lifecycle chaincode approveformyorg -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 --channelID mychannel --name basic --version 1.0 --package-id $PKGID --sequence 1 setGlobals 1 ../bin/peer lifecycle chaincode approveformyorg -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 --channelID mychannel --name basic --version 1.0 --package-id $PKGID --sequence 1 ../bin/peer lifecycle chaincode commit -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 --channelID mychannel --name basic --peerAddresses localhost:7051 --tlsRootCertFiles $PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1.0 --sequence 1

Here are the containers running:

At this point, the chaincode is deployed in the channel and is started as external service. We should now be able to do query/invoke.

Invoke:

../bin/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 mychannel -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":"InitLedger","Args":[]}'

Query:

../bin/peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

Possible Errors

If you get the below error during invoke,

Error: endorsement failure during invoke. response: status:500 message:"error in simulation: failed to execute transaction 9ca347bc88562f7913d943b96f4035e81218fb57b1b1c68afcc312dd8339546e: could not launch chaincode basic_1.0:919fda9ae8235c8c2430034b019796e96248f44ad20e444c2aac533b014d5f44: error building chaincode: malformed chaincode info at '/var/hyperledger/production/externalbuilder/builds/basic_1.0-919fda9ae8235c8c2430034b019796e96248f44ad20e444c2aac533b014d5f44/release/chaincode/server/connection.json': unexpected end of JSON input"

Then go inside the peer0 of org1

docker exec -it peer0.org1.example.com /bin/sh cd /var/hyperledger/production/externalbuilder/builds/basic_1.0-919fda9ae8235c8c2430034b0197 96e96248f44ad20e444c2aac533b014d5f44/release/chaincode/server

Add the below json to connection.json file

{ "address": "asset-transfer-basic.org1.example.com:9999", "dial_timeout": "10s", "tls_required": false }

Repeat the above steps for peer0 of org2. This should fix the issue.

Incase of any queries, do leave a comment.

Originally published at https://saifworks.hashnode.dev.

Blockchain developer