PolarSPARC

Chaincode on Hyperledger Fabric 2.x Test Network (ARM64 Edition)


Bhaskar S 09/23/2022


Overview

In the article Setup Hyperledger Fabric 2.x Test Network, we demonstrated how one can setup the test network using the docker images we built in Building Docker Images for Hyperledger Fabric 2.x.

In this article, we will use test network to prove we can install and invoke a basic chaincode (smart contract) sample called Asset Transfer Basic from the Hyperledger samples.

Pre-requisites

Assuming that we are logged in as bswamina and the current working directory is the home directory /home/bswamina.

Also, we will assume that the host is using a static ip address and is set to 192.168.1.45 (one can pick their favorite).

Ensure we have the Hyperledger Fabric Samples source code that we cloned during the test network setup in the directory $HOME/hyperledger.

The asset transfer basic sample is located under the directory $HOME/hyperledger/asset-transfer-basic.

Ensure we have all the the Docker images by executing the following command:

$ docker images

The following would be the typical output:

Output.1

REPOSITORY                TAG                 IMAGE ID       CREATED          SIZE
bswamina/fabric-tools     2.4.6               773fcf5b8132   6 minutes ago    469MB
bswamina/fabric-peer      2.4.6               b9e6c7a86e29   11 minutes ago   50.2MB
bswamina/fabric-orderer   2.4.6               25668ac89999   15 minutes ago   35.2MB
bswamina/fabric-ccenv     2.4.6               7ade519a0116   19 minutes ago   530MB
bswamina/fabric-baseos    2.4.6               d420699eef0d   20 minutes ago   6.56MB
bswamina/fabric-ca        1.5.5               dc9e62641828   29 minutes ago   78.2MB

Chaincode Test

Now, it is time to setup the directory structure for the chaincode installation by executing the following commands:

$ cd $HOME

$ mkdir -p hlf_v2/cc-go/.cache

Now, it is time to copy the chaincode files from the asset transfer basic sample by executing the following commands:

$ cd $HOME/hlf_v2

$ cp -R ../hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/* ./cc-go

We will need to modify the cc-go/go.mod file to update the golang version to 1.18.

Next, we need to download and store all the chaincode dependent third-party golang libraries locally. To do that, execute the following commands:

$ cd $HOME/hlf_v2/cc-go

$ GOPROXY=https://goproxy.io,direct GO111MODULE=on go mod vendor

cd ..

The following would be the typical output:

Output.2

go: downloading github.com/hyperledger/fabric-contract-api-go v1.1.0
go: downloading github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e
go: downloading github.com/golang/protobuf v1.3.2
go: downloading github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212
go: downloading github.com/stretchr/testify v1.5.1
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading github.com/pmezard/go-difflib v1.0.0
go: downloading gopkg.in/yaml.v2 v2.2.8
go: downloading google.golang.org/grpc v1.23.0
go: downloading github.com/xeipuuv/gojsonschema v1.2.0
go: downloading github.com/go-openapi/spec v0.19.4
go: downloading github.com/gobuffalo/packr v1.30.1
go: downloading github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415
go: downloading google.golang.org/genproto v0.0.0-20180831171423-11092d34479b
go: downloading golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
go: downloading golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542
go: downloading github.com/gobuffalo/envy v1.7.0
go: downloading github.com/gobuffalo/packd v0.3.0
go: downloading github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f
go: downloading github.com/go-openapi/jsonpointer v0.19.3
go: downloading github.com/go-openapi/jsonreference v0.19.2
go: downloading github.com/go-openapi/swag v0.19.5
go: downloading github.com/joho/godotenv v1.3.0
go: downloading github.com/rogpeppe/go-internal v1.3.0
go: downloading github.com/PuerkitoBio/purell v1.1.1
go: downloading github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e
go: downloading golang.org/x/text v0.3.2
go: downloading github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578

Now it is time to create the chaincode package for installation on the peers (org1 and org2) by executing the following command:

$ docker run --rm -e GOCACHE="/hlf_v2/cc-go/.cache" -e GO111MODULE=on -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 /usr/local/bin/peer lifecycle chaincode package /hlf_v2/cc-go/basic.tar.gz --path /hlf_v2/cc-go/ --lang golang --label basic_1.0

There will be no output and the chaincode package basic.tar.gz will be created in the directory hlf_v2/cc-go.

We are now ready to install the asset transfer basic smart contract (chaincode) package on our two peers - org1 and org2. The chaincode needs to be installed on every peer that will endorse a transaction. Because we have set the endorsement policy to require endorsements from both peers org1 and org2, we need to install the chaincode on both peers.

To install the chaincode package basic.tar.gz on the peer org1, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org1MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:7051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode install /hlf_v2/cc-go/basic.tar.gz

The following would be the typical output:

Output.3

2022-09-18 22:40:03.036 UTC 0001 INFO [cli.lifecycle.chaincode] submitInstallProposal -> Installed remotely: response:<status:200 payload:"\nJbasic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93\022\tbasic_1.0" > 
2022-09-18 22:40:03.036 UTC 0002 INFO [cli.lifecycle.chaincode] submitInstallProposal -> Chaincode code package identifier: basic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93

!!! ATTENTION !!!

The volume mapping /var/run/docker.sock:/var/run/docker.sock in the docker compose file docker/compose-test-net.yaml is EXTREMELY IMPORTANT !!!

Else, one will encounter the following error:

Error: chaincode install failed with status: 500 - failed to invoke backing implementation of 'InstallChaincode': could not build chaincode: docker build failed: docker image inspection failed: Get "http://unix.sock/images/dev-peer0.org1.example.com-basic_1.0-2e20ce421c8037420718c8a3918a1eea76343b7361fffdac454181c54e5736c7-cac7c8ab67a9b044b101664a48f73538c06928a9b544999ddf9f5346f04cc62a/json": dial unix /var/run/docker.sock: connect: no such file or directory

To install the chaincode package basic.tar.gz on the peer org2, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org2MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:9051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode install /hlf_v2/cc-go/basic.tar.gz

The following would be the typical output:

Output.4

2022-09-18 22:41:16.614 UTC 0001 INFO [cli.lifecycle.chaincode] submitInstallProposal -> Installed remotely: response:<status:200 payload:"\nJbasic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93\022\tbasic_1.0" > 
2022-09-18 22:41:16.614 UTC 0002 INFO [cli.lifecycle.chaincode] submitInstallProposal -> Chaincode code package identifier: basic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93

To verify the installation of the chaincode package and get the associated Package ID from the peer org1, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org1MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:7051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode queryinstalled

The following would be the typical output:

Output.5

Installed chaincodes on peer:
Package ID: basic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93, Label: basic_1.0

To verify the installation of the chaincode package and get the associated Package ID from the peer org2, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org2MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:9051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode queryinstalled

The following would be the typical output:

Output.6

Installed chaincodes on peer:
Package ID: basic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93, Label: basic_1.0

From the Output.5 and Output.6 above, we can infer the Package ID for the installed chaincode to be basic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93. We will need this for the next step.

The installed the chaincode needs to approve the chaincode definition (name, version, endorsement policy, etc) by a majority of channel members. Since the test network has only two peer members (org1 and org2) on the channel, we need approval from both the peers org1 and org2.

In order to approve the chaincode definition, we need the value of the Package ID.

To submit the approval of the chaincode definition from the the peer org1 using the Admin role, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org1MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:7051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode approveformyorg -o 192.168.1.45:7050 --ordererTLSHostnameOverride orderer.example.com --channelID channel1 --name basic --version 1.0 --package-id basic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93 --sequence 1 --tls --cafile "/hlf_v2/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"

The following would be the typical output:

Output.7

2022-09-18 22:49:13.798 UTC 0001 INFO [chaincodeCmd] ClientWait -> txid [9cdd194bf1b3d40814c32bf0b277c8b6afc7b43fabcf0987d00fde287103a78f] committed with status (VALID) at 192.168.1.44:7051

To submit the approval of the chaincode definition from the the peer org2 using the Admin role, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org2MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:9051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode approveformyorg -o 192.168.1.45:7050 --ordererTLSHostnameOverride orderer.example.com --channelID channel1 --name basic --version 1.0 --package-id basic_1.0:2ba90fd25490bba3b6c7fe1cb3d08a6de31cecb13d7d375c6cdca306be369f93 --sequence 1 --tls --cafile "/hlf_v2/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"

The following would be the typical output:

Output.8

2022-09-18 22:46:19.840 UTC 0001 INFO [chaincodeCmd] ClientWait -> txid [fc4ac76fe17d56ec3c76d0b7180cd576f1e0ac5c01a5fd36dd4cdff2ff3ba173] committed with status (VALID) at 192.168.1.44:9051

To verify the chaincode definition approvals from the channel members on the test network, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org1MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:7051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode checkcommitreadiness --channelID channel1 --name basic --version 1.0 --sequence 1 --tls --cafile "/hlf_v2/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --output json

The following would be the typical output:

Output.9

{
  "approvals": {
    "Org1MSP": true,
    "Org2MSP": true
  }
}

From the Output.9 above, we can confirm that both the peers (org1 and org2) have approved the chaincode definition.

We now need to commit the approved chaincode definition to the channel.

To commit the chaincode definition to the channel channel1, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org1MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:7051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode commit -o 192.168.1.45:7050 --ordererTLSHostnameOverride orderer.example.com --channelID channel1 --name basic --version 1.0 --sequence 1 --tls --cafile "/hlf_v2/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses 192.168.1.45:7051 --tlsRootCertFiles "/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses 192.168.1.45:9051 --tlsRootCertFiles "/hlf_v2/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"

The following would be the typical output:

Output.10

2022-09-18 22:52:46.193 UTC 0001 INFO [chaincodeCmd] ClientWait -> txid [82f5ee1540c500d12209d328bcf654128dc9e9d7bc6dd7e0d0f4163aa3de98f7] committed with status (VALID) at 192.168.1.44:7051
2022-09-18 22:52:46.194 UTC 0002 INFO [chaincodeCmd] ClientWait -> txid [82f5ee1540c500d12209d328bcf654128dc9e9d7bc6dd7e0d0f4163aa3de98f7] committed with status (VALID) at 192.168.1.44:9051

To verify the chaincode definition has been committed to the channel channel1, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org1MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:7051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer lifecycle chaincode querycommitted --channelID channel1 --name basic --cafile "/hlf_v2/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"

The following would be the typical output:

Output.11

Committed chaincode definition for chaincode 'basic' on channel 'channel1':
Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true, Org2MSP: true]

Once the chaincode definition is committed to the channel, the chaincode will be started on both the peer members of the channel (as a docker container).

Now is the time for the real test - to invoke the chaincode to initialize the assets on the ledger.

To invoke the command on the chaincode to initialize the assets on the ledger, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org1MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:7051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer chaincode invoke -o 192.168.1.45:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "/hlf_v2/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID channel1 --name basic --peerAddresses 192.168.1.45:7051 --tlsRootCertFiles "/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses 192.168.1.45:9051 --tlsRootCertFiles "/hlf_v2/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"InitLedger","Args":[]}'

The following would be the typical output:

Output.12

2022-09-18 23:03:21 UTC 0001 INFO [chaincodeCmd] chaincodeInvokeOrQuery -> Chaincode invoke successful. result: status:200

!!! ATTENTION !!!

The value of NetworkMode: tag under vm: tag in the peer yaml config/peercfg/core.yaml MUST match the name of the docker network docker_default and the variables CORE_VM_ENDPOINT=unix:///var/run/docker.sock and CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=docker_default under the environment: tag MUST be defined as shown.

Else, one will encounter the following error:

Error starting asset-transfer-basic chaincode: connection error: desc = "transport: error while dialing: dial tcp: lookup peer0.org2.example.com on 192.168.1.1:53: no such host"

Finally, to query the chaincode state, execute the following command:

$ docker run --rm -e FABRIC_CFG_PATH="/hlf_v2/config/peercfg" -e CORE_PEER_TLS_ENABLED=true -e CORE_PEER_LOCALMSPID="Org1MSP" -e CORE_PEER_TLS_ROOTCERT_FILE="/hlf_v2/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -e CORE_PEER_MSPCONFIGPATH="/hlf_v2/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" -e CORE_PEER_ADDRESS="192.168.1.45:7051" -u $(id -u ${USER}):$(id -g ${USER}) -v /home/bswamina/hlf_v2:/hlf_v2 bswamina/fabric-tools:2.4.6 peer chaincode query -C channel1 -n basic -c '{"Args":["GetAllAssets"]}'

The following would be the typical output:

Output.13

[{"AppraisedValue":300,"Color":"blue","ID":"asset1","Owner":"Tomoko","Size":5},{"AppraisedValue":400,"Color":"red","ID":"asset2","Owner":"Brad","Size":5},{"AppraisedValue":500,"Color":"green","ID":"asset3","Owner":"Jin Soo","Size":10},{"AppraisedValue":600,"Color":"yellow","ID":"asset4","Owner":"Max","Size":10},{"AppraisedValue":700,"Color":"black","ID":"asset5","Owner":"Adriana","Size":15},{"AppraisedValue":800,"Color":"white","ID":"asset6","Owner":"Michel","Size":15}]

WALLA !!! We have successfully demonstrated the installation and execution of the asset tranfer basic chaincode on our test network using our custom build Hyperledger Fabric docker images for the arm64 platform.

The following is the link to the Github Repo that provides all the directory structure along with the related config yaml files and the chaincode used in this series:


References

Setup Hyperledger Fabric 2.x Test Network (ARM64 Edition)

Building Docker Images for Hyperledger Fabric 2.x (ARM64 Edition)



© PolarSPARC