Fabrc 2.0 External Chain Code Development Tutorial

Keywords: Blockchain JSON github network Kubernetes

A new feature introduced in Hyperledger Fabric 2.0 is the ability to use external chain code launchers, which are ideal for using kubenetes or dowcker swarm to manage node and chain code containers in a unified manner.In this article, we will learn how to deploy chain codes in a K8s cluster using an external chain code launcher.

1. Prerequisites for Fabric External Chain Code Experiment

Hyperledger Fabric Block Chain Development Tutorial: Fabric Node.js Development Details | Fabric Java Development Details | Fabric Golang Development Details

Here are some prerequisites for our experiment

  • A kubenetes cluster where you can use minikube or a single-node kubeadmin.In this article we use kubeadmin
  • hyperledger fabric 2.0.1 docker mirror
  • hyperledger fabric 2.0.1 precompiler.We need tools to create cryptographic data and channel transaction profiles.From Here Download.
  • from Here Download the code for this article

2. Install precompiler

Install the precompiler using the following commands:

wget https://github.com/hyperledger/fabric/releases/download/v2.0.1/hyperledger-fabric-linux-amd64-2.0.1.tar.gz

tar -xzf hyperledger-fabric-linux-amd64-2.0.1.tar.gz# Move to the bin path

mv bin/* /bin# Check that you have successfully installed the tools by executing

configtxgen --version# Should print the following output:
# configtxgen:
#  Version: 2.0.1
#  Commit SHA: 1cfa5da98
#  Go version: go1.13.4
#  OS/Arch: linux/amd64

3. Start Hyperledger Fabric Network

Once we have started the kubernetes cluster, we can start the Fabric network.But first we need to generate the basic cryptographic data and the web creation block.There are some modifications in configtx.yaml to accommodate the new ones in fabric 2.0 lifecycle chaincode Command, these modifications are necessary to use the external chain code launcher.

Fabric block chain network contains three RAFT sorting service nodes, two institutions org1 and org2 each contain one peer node and one CA.This information is already encoded in the configtx.yaml and crypto-config.yaml files and does not need to be modified.

With the configuration file, we can now generate cryptographic data and Genesis blocks for the fabricblock chain network.We use the fabricOps.sh script:

$ ./fabricOps.sh start

The above command generates all cryptographic data, such as certificates for nodes and CA s, and the creation block of the channel.

Now you need to create a new k8s namespace for the Hyperledger Fabric workload with the following commands:

$ kubectl create ns hyperledger

Then create a folder to hold persistent data for the Hyperledger Fabric workload:

$ mkdir /home/storage

Now you can deploy the Fabric sorting node:

$ kubectl create -f orderer-service/

Use the following command to check if the Fabric network is up properly:

$ kubectl get pods -n hyperledger

### Should print a similar output
NAME                        READY   STATUS    RESTARTS   AGE
orderer0-58666b6bd7-pflf7    1/1     Running   0          5m47s
orderer1-c4fd65c7d-c27ll    1/1     Running   0          5m47s
orderer2-557cb7865-wlcmh    1/1     Running   0          5m47s

Next, create the workload for org1, which mainly includes the CA and peer nodes of the deployment agency:

$ kubectl create -f org1/

Also check whether the Fabric network node is started with the following commands:

$ kubectl get pods -n hyperledger

### Should print a similar output
NAME                          READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-9px4s      1/1     Running   0          19m
cli-org1-bc9f895f6-zmmdc      1/1     Running   0          2m56s
orderer0-58666b6bd7-pflf7      1/1     Running   0          79m
orderer1-c4fd65c7d-c27ll      1/1     Running   0          79m
orderer2-557cb7865-wlcmh      1/1     Running   0          79m
peer0-org1-798b974467-vv4zz   1/1     Running   0          19m

Repeat the steps above to load the org2 workload:

$ kubectl create -f org2/

Check the Fabric network:

$ kubectl get pods -n hyperledger

### Should print a similar output
NAME                          READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-9px4s      1/1     Running   0          71m
ca-org2-7454f69c48-q8lft      1/1     Running   0          2m20s
cli-org1-bc9f895f6-zmmdc      1/1     Running   0          55m
cli-org2-7779cc8788-8q4ns     1/1     Running   0          2m20s
orderer0-58666b6bd7-pflf7      1/1     Running   0          131m
orderer1-c4fd65c7d-c27ll      1/1     Running   0          131m
orderer2-557cb7865-wlcmh      1/1     Running   0          131m
peer0-org1-798b974467-vv4zz   1/1     Running   0          71m
peer0-org2-5849c55fcd-mbn5h   1/1     Running   0          2m19s

3. Set up channels for Fabric networks

Once the workload on the Fabric network is deployed, we can start creating channels and adding peer nodes to them.cli into org1:

$ kubectl exec -it cli_org1_pod_name sh -n hyperledger

Within this pod, execute the following command:

$ peer channel create -o orderer0:7050 -c mychannel -f ./scripts/channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA

### Should print a similar output
2020-03-06 11:54:57.582 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-03-06 11:54:58.903 UTC [cli.common] readBlock -> INFO 002 Received block: 0

Now that the mychannel channel channel has been created, add the peer node of org1 to the channel:

$ peer channel join -b mychannel.block

### Should print a similar output
2020-03-06 12:01:41.608 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-03-06 12:01:41.688 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel

The same operation adds the peer node of org2 to the channel.However, since org1 has created channels, we need to extract the channel creation block from the sorting service.First enter the pod:

$ kubectl exec -it cli_org2_pod_name sh -n hyperledger

Then do the following within the pod:

$ peer channel fetch 0 mychannel.block -c mychannel -o orderer0:7050 --tls --cafile $ORDERER_CA

### Should print a similar output
2020-03-06 12:18:14.880 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-03-06 12:18:14.895 UTC [cli.common] readBlock -> INFO 002 Received block: 0

Then join the channel:

$ peer channel join -b mychannel.block

### Should print a similar output
2020-03-06 12:20:41.475 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-03-06 12:20:41.561 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel

Check if the current node has joined the channel with the following command:

$ peer channel list

### Should print a similar output
2020-03-06 12:22:41.102 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined: 
mychannel

4. Install external chain code on Fabric node

Now let's get to the really interesting part.We will deploy marbles chain codes as external chain codes.You can do it in Fabric-samples The original chain code was found in, but in order to deploy it as an external chain code, we need to make some modifications in the imports and init functions. To declare it as an external chain code server.

The new version of the Hipperledger Fabric also includes a new chain code processing process to support the external installation and startup of chain codes.In order to use the external chain code feature, we also need to use this new process.

The first thing to do is configure the peer node to handle external chain codes.External chain code builder is based on buildpack Implementation, so we create three scripts: detect, build, and release.These three scripts must be defined within the peer container.You can Find these scripts in the buildpack/bin directory.

The chain code builder is defined in builders-config.yaml in the org1 directory, where the Custom Builder configuration is:

  # List of directories to treat as external builders and launchers for
  # chaincode. The external builder detection processing will iterate over the
  # builders in the order specified below.
  externalBuilders:
    - name: external-builder
      path: /builders/external
      environmentWhitelist:
         - GOPROXY

kubernetes uses environment variables to configure peer nodes, which override the defaults in core.yaml.

Fabric 2.0 packages and installs chain codes differently from previous versions.Because we want to use the external chain code feature, the chain code does not need to be compiled and installed in the peer's pod, but in another pod.The only information needed in the peer process is the information used to connect the external chain code process.

To do this, we need some preparation for packaging chain codes.A connection.json file is required that contains information about connecting to an external chain code server, such as address, TLS certificate, connection timeout configuration, and so on.

{
    "address": "chaincode-marbles-org1.hyperledger:7052",
    "dial_timeout": "10s",
    "tls_required": false,
    "client_auth_required": false,
    "client_key": "-----BEGIN EC PRIVATE KEY----- ... -----END EC PRIVATE KEY-----",
    "client_cert": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----",
    "root_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----"
}

This file needs to be packaged into a tar file, code.tar.gz, and compressed using the following commands:

$ cd chaincode/packaging
$ tar cfz code.tar.gz connection.json

Once we have the code.tar.gz file, we need to repackage it with another file, metadata.json.Chain code type, path, label and so on are included in metadata.json:

{"path":"","type":"external","label":"marbles"}

Package using the following commands:

$ tar cfz marbles-org1.tgz code.tar.gz metadata.json

Once we have the packaged file above, we can use the new one lifecycle chaincode install Command to install chain code:

$ peer lifecycle chaincode install marbles-org1.tgz

### Should print a similar output
2020-03-07 14:33:18.120 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nGdmarbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064\022\006degree" > 
2020-03-07 14:33:18.126 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064

Write down the chain code package identifier above, which we will use next, but you can also query the chain code package identifier at any time with the following command:

$ peer lifecycle chaincode queryinstalled

### Should print a similar output
Installed chaincodes on peer:
Package ID: marbles:030eec59c7d74fbb4e9fd57bbd50bb904a715ffb9de8fea85b6a6d4b8ca9ea12, Label: marbles

Now let's repeat the steps above for org2, but since we want to use another pod to provide chain code services for the peer nodes of org2, So we need to modify the address configuration in connection.json:

"address": "chaincode-marbles-org2.hyperledger:7052",

Then repeat the previous steps to execute the following command in the cli pod of org2:

$ rm -f code.tar.gz
$ tar cfz code.tar.gz connection.json
$ tar cfz marbles-org2.tgz code.tar.gz metadata.json
$ peer lifecycle chaincode install marbles-org2.tgz

### Should print a similar output
2020-03-07 15:10:15.093 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nGmarbles:c422c797444e4ee25a92a8eaf97765288a8d68f9c29cedf1e0cd82e4aa2c8a5b\022\006degree" > 
2020-03-07 15:10:15.093 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marbles:c422c797444e4ee25a92a8eaf97765288a8d68f9c29cedf1e0cd82e4aa2c8a5b

It also records the identifier of the chain code package, which should be different from org1.

What happens inside the peer when we install the chain code?If an external builder or launcher is defined, then the built-in chain code building process is not performed.Since we have defined an external builder, the external build scripts will be executed in the following order:

The detect script detects whether the chain code to be installed is configured as an external type in metadata.json.If the script fails, peer will assume that the external builder does not need to build chain codes and try other external builders until the built-in docker build process is used when no external builder is finally available.

#!/bin/sh

# The bin/detect script is responsible for determining whether or not a buildpack 
# should be used to build a chaincode package and launch it. 
# 
# The peer invokes detect with two arguments:
# bin/detect CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR
#
# When detect is invoked, CHAINCODE_SOURCE_DIR contains the chaincode source and 
# CHAINCODE_METADATA_DIR contains the metadata.json file from the chaincode package installed to the peer. 
# The CHAINCODE_SOURCE_DIR and CHAINCODE_METADATA_DIR should be treated as read only inputs. 
# If the buildpack should be applied to the chaincode source package, detect must return an exit code of 0; 
# any other exit code will indicate that the buildpack should not be applied.

CHAINCODE_METADATA_DIR="$2"

set -euo pipefail

# use jq to extract the chaincode type from metadata.json and exit with
# success if the chaincode type is golang
if [ "$(cat "$CHAINCODE_METADATA_DIR/metadata.json" | sed -e 's/[{}]/''/g' | awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'type'\042/){print $(i+1)}}}' | tr -d '"')" = "external" ]; then
    exit 0
fi

exit 1

If the detect script succeeds, the build script is called.If chain codes are built inside a peer, the script should generate binaries.However, since we want to be an external service, simply copy the connection.json file to the build output directory.

#!/bin/sh

# The bin/build script is responsible for building, compiling, or transforming the contents 
# of a chaincode package into artifacts that can be used by release and run.
#
# The peer invokes build with three arguments:
# bin/build CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR BUILD_OUTPUT_DIR
#
# When build is invoked, CHAINCODE_SOURCE_DIR contains the chaincode source and 
# CHAINCODE_METADATA_DIR contains the metadata.json file from the chaincode package installed to the peer.
# BUILD_OUTPUT_DIR is the directory where build must place artifacts needed by release and run. 
# The build script should treat the input directories CHAINCODE_SOURCE_DIR and 
# CHAINCODE_METADATA_DIR as read only, but the BUILD_OUTPUT_DIR is writeable.

CHAINCODE_SOURCE_DIR="$1"
CHAINCODE_METADATA_DIR="$2"
BUILD_OUTPUT_DIR="$3"

set -euo pipefail

#external chaincodes expect connection.json file in the chaincode package
if [ ! -f "$CHAINCODE_SOURCE_DIR/connection.json" ]; then
    >&2 echo "$CHAINCODE_SOURCE_DIR/connection.json not found"
    exit 1
fi

#simply copy the endpoint information to specified output location
cp $CHAINCODE_SOURCE_DIR/connection.json $BUILD_OUTPUT_DIR/connection.json

if [ -d "$CHAINCODE_SOURCE_DIR/metadata" ]; then
    cp -a $CHAINCODE_SOURCE_DIR/metadata $BUILD_OUTPUT_DIR/metadata
fi

exit 0

Finally, once the build script is executed, the release script is called.This script is responsible for providing the connection.json file to the peer node, and it only needs to be placed in the release output directory.So peer now knows how to call chain codes.

#!/bin/sh

# The bin/release script is responsible for providing chaincode metadata to the peer. 
# bin/release is optional. If it is not provided, this step is skipped. 
#
# The peer invokes release with two arguments:
# bin/release BUILD_OUTPUT_DIR RELEASE_OUTPUT_DIR
#
# When release is invoked, BUILD_OUTPUT_DIR contains the artifacts 
# populated by the build program and should be treated as read only input. 
# RELEASE_OUTPUT_DIR is the directory where release must place artifacts to be consumed by the peer.

set -euo pipefail

BUILD_OUTPUT_DIR="$1"
RELEASE_OUTPUT_DIR="$2"

# copy indexes from metadata/* to the output directory
# if [ -d "$BUILD_OUTPUT_DIR/metadata" ] ; then
#    cp -a "$BUILD_OUTPUT_DIR/metadata/"* "$RELEASE_OUTPUT_DIR/"
# fi

#external chaincodes expect artifacts to be placed under "$RELEASE_OUTPUT_DIR"/chaincode/server
if [ -f $BUILD_OUTPUT_DIR/connection.json ]; then
   mkdir -p "$RELEASE_OUTPUT_DIR"/chaincode/server
   cp $BUILD_OUTPUT_DIR/connection.json "$RELEASE_OUTPUT_DIR"/chaincode/server

   #if tls_required is true, copy TLS files (using above example, the fully qualified path for these fils would be "$RELEASE_OUTPUT_DIR"/chaincode/server/tls)

   exit 0
fi

exit 1

5. Construction and Deployment of Fabric External Chain Code

Once we have chain codes installed on peer nodes, they can be built and deployed on our kubernetes cluster.Let's take a look at the necessary changes.

First you need to import some necessary modules:

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"
	"os"

	"github.com/hyperledger/fabric-chaincode-go/shim"
	pb "github.com/hyperledger/fabric-protos-go/peer"
)

One thing to point out is that you need to define the go.mod file before building code.The latest version of the shim module includes support for external chain code features - only the go chain code development kit currently supports external chain code.

module github.com/marbles
  
go 1.12

require (
        github.com/hyperledger/fabric-chaincode-go v0.0.0-20200128192331-2d899240a7ed
        github.com/hyperledger/fabric-protos-go v0.0.0-20200124220212-e9cfc186ba7b
        golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
        golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 // indirect
        golang.org/x/text v0.3.2 // indirect
        google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5 // indirect
)

Other changes include modifying the chaining code server's listening address, port, and so on.Because we want to use kubernetes'yaml description file to modify these configurations, we use the os module to get these values:

func main() {

	server := &shim.ChaincodeServer{
		CCID:    os.Getenv("CHAINCODE_CCID"),
		Address: os.Getenv("CHAINCODE_ADDRESS"),
		CC:      new(SimpleChaincode),
		TLSProps: shim.TLSProperties{
				Disabled: true,
		},
	}

	// Start the chaincode external server
	err := server.Start()

	if err != nil {
		fmt.Printf("Error starting Marbles02 chaincode: %s", err)
	}
}

Now you can use the following Dockerfile to build a chain code image:

# This image is a microservice in golang for the Degree chaincode
FROM golang:1.13.8-alpine AS build

COPY ./ /go/src/github.com/marbles
WORKDIR /go/src/github.com/marbles

# Build application
RUN go build -o chaincode -v .

# Production ready image
# Pass the binary to the prod image
FROM alpine:3.11 as prod

COPY --from=build /go/src/github.com/marbles/chaincode /app/chaincode

USER 1000

WORKDIR /app
CMD ./chaincode

Chain codes are constructed using an alpine image of golang.Perform the following command to create a chain code image:

$ docker build -t chaincode/marbles:1.0 .

If everything goes well, you can deploy it.Modify the CHAINCODE_CCID variable in the chain code deployment files org1-chaincode-deployment.yaml and org2-chaincode-deployment.yaml for the chain code you need to install.

#---------------- Chaincode Deployment ---------------------
apiVersion: apps/v1 # for versions before 1.8.0 use apps/v1beta1
kind: Deployment
metadata:
  name: chaincode-marbles-org1
  namespace: hyperledger
  labels:
    app: chaincode-marbles-org1
spec:
  selector:
    matchLabels:
      app: chaincode-marbles-org1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: chaincode-marbles-org1
    spec:
      containers:
        - image: chaincode/marbles:1.0
          name: chaincode-marbles-org1
          imagePullPolicy: IfNotPresent
          env:
            - name: CHAINCODE_CCID
              value: "marbles:d8140fbc1a0903bd88611a96c5b0077a2fdeef00a95c05bfe52e207f5f9ab79d"
            - name: CHAINCODE_ADDRESS
              value: "0.0.0.0:7052"
          ports:
            - containerPort: 7052

Then deploy:

$ kubectl create -f chaincode/k8s

Now the fabric s network should look like this:

$ kubectl get pods -n hyperledgerNAME                                      READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-tx59g                  1/1     Running   0          19h
ca-org2-7454f69c48-nfzsq                  1/1     Running   0          19h
chaincode-marbles-org1-6fc8858855-wdz7z   1/1     Running   0          20m
chaincode-marbles-org2-77bf56fdfb-6cdfm   1/1     Running   0          14m
cli-org1-589944999c-cvgbx                 1/1     Running   0          19h
cli-org2-656cf8dd7c-kcxd7                 1/1     Running   0          19h
orderer0-5844bd9bcc-6td8c                 1/1     Running   0          46h
orderer1-75d8df99cd-6vbjl                 1/1     Running   0          46h
orderer2-795cf7c4c-6lsdd                  1/1     Running   0          46h
peer0-org1-5bc579d766-kq2qd               1/1     Running   0          19h
peer0-org2-77f58c87fd-sczp8               1/1     Running   0          19h

Now we need to approve the chain code for each agency.This is a new feature of the chain code life cycle process, and each agency needs to agree to the definition of the new chain code.We will approve the marble chain code definition for org1.Execute the following command within the cli pod of org1, remember to modify CHAINCODE_CCID:

$ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
2020-03-08 10:02:46.192 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [4d81ea5fd494e9717a0c860812d2b06bc62e4fc6c4b85fa6c3a916eee2c78e85] committed with status (VALID)

You can check the approval status throughout the network with the following commands:

$ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-require
d --sequence 1 -o -orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
Chaincode definition for chaincode 'marbles', version '1.0', sequence '1' on channel 'mychannel' approval status by org:
org1MSP: true
org2MSP: false

Now let's approve the chain code definition for org2.Execute the following command in the cli pod of org2, remember to modify CHAINCODE_CCID:

$ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:25a9f6fe26161d29af928228ca1db0c41892e26e46335c84952336ee26d1fd93 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
2020-03-08 10:26:43.992 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [74a89f3c93c10f14c626bd4d6cb654b37889908c9e6f7b983d2cad79f1e82267] committed with status (VALID)

Check chain code submission status again:

$ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-required --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
Chaincode definition for chaincode 'marbles', version '1.0', sequence '1' on channel 'mychannel' approval status by org:
org1MSP: true
org2MSP: true

Now that we have the approval of all agencies, let's submit the chain code definition on the channel.You can do the following on any peer:

$ peer lifecycle chaincode commit -o orderer0:7050 --channelID mychannel --name marbles --version 1.0 --sequence 1 --init-required --tls true --cafile $ORDERER_CA --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
2020-03-08 14:13:49.516 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [568cb81f821698025bbc61f4c6cd3b4baf1aea632e1e1a8cfdf3ec3902d1c6bd] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:13:49.533 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [568cb81f821698025bbc61f4c6cd3b4baf1aea632e1e1a8cfdf3ec3902d1c6bd] committed with status (VALID) at peer0-org2:7051

Okay, now the chain code is ready to be queried and invoked!

6. Testing Fabric External Chain Code

We can test chain code queries and transaction calls from cli pod.First create some gems:

$ peer chaincode invoke -o orderer0:7050 --tls true --cafile $ORDERER_CA -C mychannel -n marbles --peerAddresses 
peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer
0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt -c '{"Args":["initMarble
","marble1","blue","35","tom"]}' --waitForEvent

### Should print a similar output
2020-03-08 14:23:03.569 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [83aeeaac47cf6302bc139addc4aa38116a40eaff788846d87cc815d2e1318f44] committed with status (VALID) at peer0-org2:7051
2020-03-08 14:23:03.575 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [83aeeaac47cf6302bc139addc4aa38116a40eaff788846d87cc815d2e1318f44] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:23:03.576 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200

Create another gem:

$ peer chaincode invoke -o orderer0:7050 --tls true --cafile $ORDERER_CA -C mychannel -n marbles --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt -c '{"Args":["initMarble","marble2","red","50","tom"]}' --waitForEvent

### Should print a similar output
2020-03-08 14:23:40.404 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [8391f9f8ea84887a56f99e4dc4501eaa6696cd7bd6c524e4868bd6cfd5b85e78] committed with status (VALID) at peer0-org2:7051
2020-03-08 14:23:40.434 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [8391f9f8ea84887a56f99e4dc4501eaa6696cd7bd6c524e4868bd6cfd5b85e78] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:23:40.434 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200

Query Gem Information:

$ peer chaincode query -C mychannel -n marbles -c '{"Args":["readMarble","marble1"]}'

{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}

You can also execute the following command to query the chain code log:

$ kubectl logs chaincode_pod_name -n hyperledger

### Should print a similar output
invoke is running initMarble
- start init marble
- end init marble
invoke is running initMarble
- start init marble
- end init marble
invoke is running readMarble

Original Link: Hyperledger Fabric 2.0 External Chain Code Actual Warfare-Wizard

Posted by Whetto on Thu, 12 Mar 2020 19:14:19 -0700