diff --git a/docs/tutorials/develop-chaincode.md b/docs/tutorials/develop-chaincode.md new file mode 100644 index 0000000..34fa711 --- /dev/null +++ b/docs/tutorials/develop-chaincode.md @@ -0,0 +1,153 @@ +# Developing and debuging chaincode + +Publishing a chaincode Docker image and using the image digest to deploy the chaincode works well with the [Fabric chaincode lifecycle](https://hyperledger-fabric.readthedocs.io/en/latest/chaincode_lifecycle.html), however it is not as convenient while developing and debugging chaincode. + +This tutorial describes how to deploy and debug the same chaincode using the chaincode-as-a-service builder and the [fabric-samples](https://github.com/hyperledger/fabric-samples/) nano test network. + +TODO: see also... +https://github.com/hyperledger/fabric-samples/blob/main/test-network/CHAINCODE_AS_A_SERVICE_TUTORIAL.md + +First create a directory to download all the required files and run the demo. + +```shell +mkdir hlf-debug-demo +cd hlf-debug-demo +``` + +Now follow the steps below to deploy your first smart contract using the k8s builder! + +## Download the nano test network + +Download the sample nano test network (fabric-samples isn't tagged so we'll use a known good commit). + +```shell +export FABRIC_SAMPLES_COMMIT=0db64487e5e89a81d68e6871af3f0907c67e7d75 +curl -sSL "https://github.com/hyperledger/fabric-samples/archive/${FABRIC_SAMPLES_COMMIT}.tar.gz" | tar -xzf - --strip-components=1 fabric-samples-${FABRIC_SAMPLES_COMMIT}/test-network-nano-bash +``` + +## Install the Fabric binaries + +TODO: ... if they're not already in your path! + +```shell +curl -sSLO https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh && chmod +x install-fabric.sh +./install-fabric.sh binary +``` + +## Update chaincode-as-a-service builder configuration + +The sample `core.yaml` file needs to be updated with the correct chaincode-as-a-service builder location since it assumes that the peer is running in a docker container. Either edit the `path` for the `ccaas_builder` in `externalBuilders`, or use the following [yq](https://github.com/mikefarah/yq) command. + +```shell +yq -i '( .chaincode.externalBuilders[] | select(.name == "ccaas_builder") | .path ) = strenv(PWD) + "/builders/ccaas"' config/core.yaml +``` + +## Start the nano test network + +```shell +cd test-network-nano-bash +./network.sh start +``` + +## Deploy a sample contract + +With chaincode-as-a-service you still have to go through the chaincode lifecycle once to tell Fabric where the chaincode is running but after that you can stop, restart, update, and debug the chaincode all without needing to repeat the chaincode lifecycle steps as you would do normally. +This is unlikely to be acceptable in a production environment but it is ideal in a development environment. + +```shell +cat << CONNECTIONJSON_EOF > connection.json +{ + "address": "127.0.0.1:9999", + "dial_timeout": "10s", + "tls_required": false +} +CONNECTIONJSON_EOF +``` + +```shell +cat << METADATAJSON_EOF > metadata.json +{ + "type": "ccaas", + "label": "dev-contract" +} +METADATAJSON_EOF +``` + +```shell +tar -czf code.tar.gz connection.json +tar -czf dev-contract.tgz metadata.json code.tar.gz +``` + + + +```shell +cd test-network-nano-bash +. ./peer1admin.sh +peer channel list +``` + +```shell +peer lifecycle chaincode install ../dev-contract.tgz +``` + +Set the CHAINCODE_ID environment variable for use in subsequent commands: + +```shell +export CHAINCODE_ID=$(peer lifecycle chaincode calculatepackageid ../dev-contract.tgz) && echo $CHAINCODE_ID +``` + +```shell +peer lifecycle chaincode approveformyorg -o 127.0.0.1:6050 --channelID mychannel --name dev-contract --version 1 --package-id $CHAINCODE_ID --sequence 1 --tls --cafile ${PWD}/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt +``` + +```shell +peer lifecycle chaincode commit -o 127.0.0.1:6050 --channelID mychannel --name dev-contract --version 1 --sequence 1 --tls --cafile "${PWD}"/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt +``` + +## Starting the chaincode + +Example VS Code `launch.json` configuration to debug Go chaincode. + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug chaincode", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "env": { + "CHAINCODE_SERVER_ADDRESS": "127.0.0.1:9999", + "CORE_CHAINCODE_ID_NAME": "dev-contract:48e3f422d9dc97ac3d4857f19c367def119743a19cd5fdfde1a0bc7706f10f2c" + } + } + ] +} +``` + + +Check everything is working. + +```shell +peer chaincode query -C mychannel -n dev-contract -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' +``` + +## Run transactions + + +```shell +peer chaincode invoke -o 127.0.0.1:6050 -C mychannel -n dev-contract -c '{"Args":["PutValue","asset1","green"]}' --waitForEvent --tls --cafile "${PWD}"/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt +``` + +```shell +peer chaincode query -C mychannel -n dev-contract -c '{"Args":["GetValue","asset1"]}' +``` + +--- + +TODO: Check chaincode/contract api implementations all support automatic switching between client and server mode... +- [Go contracts](https://github.com/hyperledger/fabric-contract-api-go/commit/7c7666d5dd3bdc23ace194784d123697669a3558)✅ +- Java (tbc) +- Node (tbc) diff --git a/mkdocs.yml b/mkdocs.yml index 6639e00..69be1d9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -107,4 +107,5 @@ nav: - Kubernetes namespace: configuring/kubernetes-namespace.md - Kubernetes service account: configuring/kubernetes-service-account.md - Tutorials: + - Developing and debuging chaincode: tutorials/develop-chaincode.md - Creating a chaincode package: tutorials/package-chaincode.md diff --git a/samples/go-contract/ccaas.env b/samples/go-contract/ccaas.env new file mode 100644 index 0000000..e6ea44a --- /dev/null +++ b/samples/go-contract/ccaas.env @@ -0,0 +1,24 @@ +# CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can +# connect to the chaincode server +CHAINCODE_SERVER_ADDRESS=localhost + +# CHAINCODE_ID must be set to the Package ID that is assigned to the chaincode +# on install. The `peer lifecycle chaincode queryinstalled` command can be +# used to get the ID after install if required +CHAINCODE_ID=test + +# Optional parameters that will be used for TLS connection between peer node +# and the chaincode. +# TLS is disabled by default, uncomment the following line to enable TLS connection +# CHAINCODE_TLS_DISABLED=false + +# Following variables will be ignored if TLS is not enabled. +# They need to be in PEM format +# CHAINCODE_TLS_KEY=/path/to/private/key/file +# CHAINCODE_TLS_CERT=/path/to/public/cert/file + +# The following variable will be used by the chaincode server to verify the +# connection from the peer node. +# Note that when this is set a single chaincode server cannot be shared +# across organizations unless their root CA is same. +# CHAINCODE_CLIENT_CA_CERT=/path/to/peer/organization/root/ca/cert/file