fabric-samples/test-network-k8s/docs/CHAINCODE.md
jkneubuh eeb4e611c7
Provide clear guidance for debugging Java chaincode as a service #684 (#724)
* Addresses Issue #548 by providing a simple guide for running Java chaincode as a service with a local debugger.

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* missed a couple of bash syntax errors

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* Add metadata and activate examples to the CC README

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* move ccpackage/ contents into network script

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* Fix CI test - Azure mounts git checkout at a different folder root path

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* Update test-network-k8s README with updated cc deploy commands

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* Run basic-asset transfer CI tests with Java + golang CC in Azure

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* remove (obsolete) test-net chaincode/ folder

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* Address some PR review feedback points - README reorg

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* Use the SDKs contract router Main, not a local entrypoint

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>

* bump the build - remove trailing newlines from a README

Signed-off-by: Josh Kneubuhl <jkneubuh@us.ibm.com>
2022-04-26 15:33:14 +01:00

8.5 KiB

Working with Chaincode

In this guide we will launch the Asset Transfer Basic chaincode "as a service" on the Kubernetes test network. In addition, we will demonstrate how to connect the test network to a chaincode process running on your local machine as a local binary, attached in an IDE debugger, or in a Docker container.

TL/DR :

$ ./network chaincode deploy 
✅ - Packaging chaincode folder chaincode/asset-transfer-basic ...
✅ - Transferring chaincode archive to org1 ...
✅ - Installing chaincode for org org1 ...
✅ - Launching chaincode container "ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic" ...
✅ - Activating chaincode basic_1.0:5e0c4db62c1f91599f58dcbfe2c37566453b1e02933646c49ba46f196723cc30 ...
🏁 - Chaincode is ready.
$ ./network chaincode invoke '{"Args":["CreateAsset","1","blue","35","tom","1000"]}' 
2021-10-03 17:23:43.508 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 

$ ./network chaincode query '{"Args":["ReadAsset","1"]}' | jq 
{
  "ID": "1",
  "color": "blue",
  "size": 35,
  "owner": "tom",
  "appraisedValue": 1000
}

Running Smart Contracts on Kubernetes

In the Kubernetes Test Network, smart contracts are developed with the Chaincode as a Service pattern, relying on an embedded External Builder to avoid the use of a Docker daemon. With Chaincode-as-a-Service, smart contracts are deployed to Kubernetes as Services, Deployments, and Pods. When invoking smart contracts, the Peer network connects to the grpc receiver through the port exposed by the chaincode's Kube Service as described in the chaincode connection.json.

Before installing chaincode to the network, a smart contract must:

  • Utilize the ChaincodeServer grpc receiver, as described in the Fabric Operations Guide.

  • Run as a Docker image published to a container registry.

  • Maintain a connection.json and metadata.json files in the chaincode/$CHAINCODE_NAME folder.

  • Accept the CHAINCODE_ID environment variable: CHAINCODE_LABEL:sha_256(chaincode.tar.gz).

Deploying Chaincode to the Network

✅ - Packaging chaincode "asset-transfer-basic" archive ... 
✅ - Deploying chaincode "asset-transfer-basic" for org org1 ...

When working with chaincode, the ./network script includes two parameters that define the Docker image launched in the cluster and the chaincode metadata:

  • ${TEST_NETWORK_CHAINCODE_NAME:-asset-transfer-basic} refers to the name associated with the chaincode.
    While packaging and deploying to the network, the scripts/chaincode.sh script uses this string to search the local /chaincode folder for associated metadata and connection json descriptor files.

  • ${TEST_NETWORK_CHAINCODE_IMAGE:-ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic} defines the container image that will be used when running the chaincode in Kubernetes.

To deploy the chaincode, the network script will:

  1. Read the connection.json and metadata.json files from the /chaincode/${TEST_NETWORK_CHAINCODE_NAME} folder, bundling the files into a chaincode tar.gz archive.

  2. Install the chaincode archive on a peer in the organization:

  export CORE_PEER_ADDRESS='${org}'-peer1:7051
  peer lifecycle chaincode install chaincode/asset-transfer-basic.tgz
  1. In typical Fabric operations, the output of the chaincode install command includes a generated ID of the chaincode archive printed to standard out. This ID is manually inspected and transcribed by the network operator when executing subsequent commands with the network peers. To avoid scraping the output of the installation command, the test network scripts precompute the chaincode ID as the sha256 checksum of the tar.gz archive.

  2. The chaincode docker image is launched using the yaml template as a Kubernetes Deployment specifying CHAINCODE_ID=sha-256(archive) in the environment and binding a Service port 9999 within the namespace. When the network sends messages to the chaincode process, it will use the host URL as defined in the connection.json, connecting to the kubernetes Service URL and Deployment.

  3. Finally, the Admin CLI issues a series of peer commands to approve and commit the chaincode for the org:

  export CORE_PEER_ADDRESS='${org}'-peer1:7051
  
  peer lifecycle \
    chaincode approveformyorg \
    --channelID '${CHANNEL_NAME}' \
    --name '${CHAINCODE_NAME}' \
    --version 1 \
    --package-id '${cc_id}' \
    --sequence 1 \
    -o org0-orderer1:6050 \
    --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem
  
  peer lifecycle \
    chaincode commit \
    --channelID '${CHANNEL_NAME}' \
    --name '${CHAINCODE_NAME}' \
    --version 1 \
    --sequence 1 \
    -o org0-orderer1:6050 \
    --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem

Invoking and Querying the Chaincode

Once the chaincode service has been deployed to the cluster, and the peers have approved the chaincode, the test scripts can issue adhoc invoke, query, and metadata requests to the network:

Invoke

$ ./network chaincode invoke '{"Args":["CreateAsset","1","blue","35","tom","1000"]}' 
2021-10-03 17:23:43.508 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 

Query

$ ./network chaincode query '{"Args":["ReadAsset","1"]}' | jq 
{
  "ID": "1",
  "color": "blue",
  "size": 35,
  "owner": "tom",
  "appraisedValue": 1000
}

Describe

$ ./network chaincode metadata | jq | head 
{
  "info": {
    "title": "undefined",
    "version": "latest"
  },
  "contracts": {
    "SmartContract": {
      "info": {
        "title": "SmartContract",
        "version": "latest"

Build a Chaincode Docker Image

Before chaincode can be started in the network, it must be compiled, linked with the grpc ChaincodeServer, embedded into a Docker image, and pushed to a container registry visible to the Kubernetes cluster.

By default, the ./network script will launch the asset-transfer-basic chaincode. When the test network installs this chaincode, there is no need to build a custom Docker image as it has previously been uploaded to a public container registry.

As an exercise, we recommend making some updates to the asset transfer basic chaincode and then running the modified smart contract on your local Kubernetes cluster. For instance, the current version of the assetTransfer.go code is completely silent, printing nothing to the log when functions are invoked in the container. Try adding some debugging information to the stdout of this process, bundling into a Docker image, and pushing the docker image to the local development container registry.

  1. Add some print statements to assetTransfer.go. E.g.:
    fmt.Printf("reading asset %s\n", id)
  1. Build the docker image locally with:
docker build -t asset-transfer-basic ../asset-transfer-basic/chaincode-external 
  1. Override the test network's default chaincode image, pointing to our local container registry:
export TEST_NETWORK_CHAINCODE_IMAGE=localhost:5000/asset-transfer-basic
  1. Publish the custom image to the local registry:
docker tag asset-transfer-basic $TEST_NETWORK_CHAINCODE_IMAGE 
docker push $TEST_NETWORK_CHAINCODE_IMAGE

Debugging Chaincode

One of the most compelling features of Fabric's Chaincode-as-a-Service pattern is that when the peer connects to a chaincode URL, it can connect back to a port on the local host. Instead of connecting to a pod running in a container within Kubernetes, the chaincode process can be launched locally as a native binary in a debugger, an IDE, or a docker image bound to the host network.

For additional details, see the debugging chaincode guide for running the basic asset transfer chaincode in an interactive development workflow.

Next Steps:

Writing a Blockchain Application