diff --git a/Dockerfile2 b/Dockerfile2 index 4f08318..6784b51 100644 --- a/Dockerfile2 +++ b/Dockerfile2 @@ -56,6 +56,8 @@ RUN groupadd -g 7051 microfab \ && mkdir -p /home/microfab/builders /home/microfab/data \ && chown -R microfab:microfab /home/microfab +RUN mkdir /working && chown microfab /working + RUN mkdir -p /opt/go /opt/node /opt/java \ && curl -sSL https://dl.google.com/go/go1.22.3.$TARGETOS-$TARGETARCH.tar.gz | tar xzf - -C /opt/go --strip-components=1 @@ -84,6 +86,8 @@ COPY --from=builder /tmp/go/src/github.com/IBM/microfab/microfabd /usr/local/bin COPY --from=builder --chown=microfab:microfab /tmp/go/src/github.com/IBM/microfab/builders/ /home/microfab/builders/ COPY --from=builder --chown=microfab:microfab /tmp/go/src/github.com/hyperledger/fabric/release/*/builders/ccaas /home/microfab/builders/ccaas +ADD examples/vscode_tasks /opt/examples/vscode_tasks + RUN sed -i 's/opt/home/g' /opt/couchdb/etc/local.d/local.ini ENV FABRIC_CFG_PATH=/etc/hyperledger/fabric @@ -120,4 +124,5 @@ ENV GOENV=/tmp/goenv ENV GOPATH=/tmp/go VOLUME /home/microfab/data +VOLUME /working ENTRYPOINT [ "tini", "--", "/usr/local/bin/docker-entrypoint.sh" ] \ No newline at end of file diff --git a/examples/vscode_tasks/README.md b/examples/vscode_tasks/README.md new file mode 100644 index 0000000..d8da0b9 --- /dev/null +++ b/examples/vscode_tasks/README.md @@ -0,0 +1,363 @@ +# Microfab VSCode User Tasks + +Microfab VSCode User Tasks provides a set of VSCode tasks that allows you to quickly start developing Hyperledger Fabric chaincode. The user tasks provide a "wrapper" for easily calling microfab to package chaincode as well as iteratively deploying chaincode in the microfab container. + +The user tasks also provide a way to easily monitor Fabric logs and launch a management shell to directly call Fabric CLI commands. + +## Requirements + +The user tasks require the following to be installed: + +- docker +- "Command Variable" VSCode extension + +NOTE: All Fabric binaries are executed from the microfab container, so microfab must be running before running any tasks. + +## Installation: + +The user tasks depend on a local directory as a storage location for chaincode source as well as scripts and a repository to store packaged chaincode. This directory is mounted as a docker host volume. Create a directory on the local machine. + +Installation is simply a matter of selecting `Code -> Settings -> User Tasks` from the VSCode menu and pasting in the folling JSON. Inside the JSON, replace the string "" with the fully qualified path to the created directory. + +``` +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "options": { + "env": { + "local_directory": "", + "CORE_PEER_MSPCONFIGPATH": "/working/_msp/Org1/org1admin/msp", + "CORE_PEER_ADDRESS": "org1peer-api.127-0-0-1.nip.io:8080", + "CORE_PEER_LOCALMSPID": "Org1MSP" + } + }, + "tasks": [ + { + "label": "Fabric - Start", + "type": "shell", + "command": "docker run -d --rm -p 8080:8080 -u microfab -v $local_directory:/working --name microfab ghcr.io/hyperledger-labs/microfab:latest && sleep 8 && cd $local_directory && docker cp microfab:opt/examples/vscode_tasks/_utils $local_directory/_utils && curl -s http://console.127-0-0-1.nip.io:8080/ak/api/v1/components | npx @hyperledger-labs/weft microfab -w _wallets -p _gateways -m _msp -f", + "problemMatcher": [] + }, + { + "label": "Fabric - Stop", + "type": "shell", + "command": "docker stop microfab", + "problemMatcher": [] + }, + { + "label": "Fabric - Show Logs", + "type": "shell", + "command": "docker logs microfab -f", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "new", + "showReuseMessage": true, + "clear": false + }, + "problemMatcher": [] + }, + { + "label": "Fabric - Peer Admin Shell", + "type": "shell", + "command": "docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID -w /working microfab bash", + "problemMatcher": [] + }, + { + "label": "Chaincode - Package open project", + "type": "shell", + "command": "cd $local_directory && rm -rf _chaincode_src && mkdir -p _chaincode_src && mkdir -p _packaged && cp -R ${workspaceFolder} _chaincode_src/temp && docker exec -it microfab /working/_utils/package.sh ${input:chaincodeName} ${input:chaincodeVersion} ${input:language} ${input:chaincodeType} /working/_chaincode_src/temp", + "problemMatcher": [] + }, + { + "label": "Chaincode - List packaged chaincode", + "type": "shell", + "command": "cd $local_directory && ls _packaged/", + "problemMatcher": [] + }, + { + "label": "Chaincode - List Committed", + "type": "shell", + "command": "docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab peer lifecycle chaincode querycommitted -C channel1", + "problemMatcher": [] + }, + { + "label": "Chaincode - List Installed ", + "type": "shell", + "command": "docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab peer lifecycle chaincode queryinstalled", + "problemMatcher": [] + }, + { + "label": "Chaincode - Deploy", + "type": "shell", + "command": "docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab /working/_utils/deployCC.sh ${input:openDialog}", + "problemMatcher": [] + } + ], + "inputs": [ + { + "type": "pickString", + "id": "language", + "description": "Chaincode language", + "options": [ + "golang", + "node", + "java" + ], + "default": "golang" + }, + { + "type": "pickString", + "id": "chaincodeType", + "description": "Chaincode Type", + "options": [ + "tar", + "cds" + ], + "default": "tar" + }, + { + "type": "promptString", + "id": "chaincodeName", + "description": "Enter the name of the chaincode" + }, + { + "type": "promptString", + "id": "chaincodeVersion", + "description": "Enter the version of the chaincode" + }, + { + "id": "openDialog", + "type": "command", + "command": "extension.commandvariable.file.openDialog", + "args": { + "canSelect": "files", + "defaultUri": "/_packaged", + "transform": { + "text": "${fileBasename}" + }, + } + } + ] +} +``` + +## Working Directory Contents + +The local working directory has the following structure: + +``` +├── _chaincode_src +├── _gateways +├── _msp +├── _packaged +├── _utils +└── _wallets +``` + +The folders _gateways, _msp and _wallets are created by microfab and contain the connection information for the Fabric network. The _chaincode_src directory is a temp directory to host the chaincode to be packaged. The process to package a chaincode is to make a make a copy of the source to the _chaincode_src directory. This is to make the source "visible" to the peer CLI from the microfab container. The _packaged directory is the target directory for storing packaged chaincode. The _utils directory contains scripts to deploy chaincode to microfab. + + +## Start the microfab container + +The microfab instance can be started by selecting `Terminal -> Run Task` in VSCode: + +![Run Task](images/RunTask.png) + +Type `Fabric` into the task filter to show the list of Fabric tasks. + +![Run Fabric](images/RunFabric.png) + +Select `Fabric - Start`. + +This will start the microfab container, download utilties and connection information to the local machine. + +``` +Executing task: docker run -d --rm -p 8080:8080 -u microfab -v $local_directory:/working --name microfab microfab:latest && sleep 8 && cd $local_directory && docker cp microfab:opt/examples/vscode_tasks/_utils $local_directory/_utils && curl -s http://console.127-0-0-1.nip.io:8080/ak/api/v1/components | npx @hyperledger-labs/weft microfab -w _wallets -p _gateways -m _msp -f + +ea46ace0571b304ab578ad2103df44ec2758b397bf8592c1f9b32208ab58b6ea +Successfully copied 34.3kB to /opt/fabric/dev/_utils +Gateway profile written to : /opt/fabric/dev/_gateways/org1gateway.json +Added identity under label ordereradmin to the wallet at /opt/fabric/dev/_wallets/Orderer +Added identity under label org1admin to the wallet at /opt/fabric/dev/_wallets/Org1 +Added identity under label org1caadmin to the wallet at /opt/fabric/dev/_wallets/Org1 + +Environment variables: +{"mspid":"Org1MSP","peers":["org1peer-api.127-0-0-1.nip.io:8080"],"ids":{"org1admin":"/opt/fabric/dev/_msp/Org1/org1admin/msp","org1caadmin":"/opt/fabric/dev/_msp/Org1/org1caadmin/msp"},"tlsrootcert":""} + +For org1admin @ Org1 use these: + +export CORE_PEER_LOCALMSPID=Org1MSP +export CORE_PEER_MSPCONFIGPATH=/opt/fabric/dev/_msp/Org1/org1admin/msp +export CORE_PEER_ADDRESS=org1peer-api.127-0-0-1.nip.io:8080 + +For org1caadmin @ Org1 use these: + +export CORE_PEER_LOCALMSPID=Org1MSP +export CORE_PEER_MSPCONFIGPATH=/opt/fabric/dev/_msp/Org1/org1caadmin/msp +export CORE_PEER_ADDRESS=org1peer-api.127-0-0-1.nip.io:8080 +Complete +``` + +## Packaging Chaincode + +Open a chaincode project in VSCode. The chaincode folder must be the top level folder in VSCode: + +![Chaincode Project](images/ChaincodeProject.png) + +The chaincode should be complete with all vendoring if required before packaging. + +Note: The microfab container must be running. + +The microfab instance can be started by selecting `Terminal -> Run Task` in VSCode: + +![Run Task](images/RunTask.png) + +Type `Chaincode` into the task filter to show the list of Fabric tasks for Chaincode. + +![Chaincode Tasks](images/ChaincodeTasks.png) + +Select `Chaincode - Package open project` + +Enter a name for the chaincode: + +![Chaincode Name](images/ChaincodeName.png) + +Enter a version for the chaincode: + +![Chaincode Version](images/ChaincodeVersion.png) + +Select the language for the chaincode: + +![Chaincode Language](images/ChaincodeLanguage.png) + +Select the package type for the chaincode: + +![Chaincode Type](images/ChaincodeType.png) + +The packaged chaincode will be copied to the `_packaged` directory in the local working directory. + +## Deploy Chaincode + +The packaged chaincode can be deployed by selecting `Terminal -> Run Task` in VSCode: + +Type `Chaincode` into the task filter to show the list of Fabric tasks for Chaincode. + +![Chaincode Tasks](images/ChaincodeTasks.png) + +Select `Chaincode - Deploy` + +![Deploy Chaincode](images/DeployChaincode.png) + +Note: `Fabric - Show Logs` can be used to show the peer logs as the chaincode lifecycle process is completed. + +``` +Chaincode definition committed on channel 'channel1' +Querying chaincode definition on org1peer on channel 'channel1'... +Attempting to Query committed status on org1peer, Retry after 3 seconds. ++ peer lifecycle chaincode querycommitted --channelID channel1 --name asset ++ res=0 +Committed chaincode definition for chaincode 'asset' on channel 'channel1': +Version: 1.0.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc, Approvals: [Org1MSP: true] +Query chaincode definition successful on org1peer on channel 'channel1' +``` + +## List Packaged Chaincode + +Packaged chaincodes can be shown by running `Terminal -> Run Task -> Chaincode - List packaged chaincode` + +Example: + +``` +Executing task: cd $local_directory && ls _packaged/ + +asset_1.0.0.tar.gz +``` + +## List Installed Chaincode + +Installed chaincodes can be shown by running `Terminal -> Run Task -> Chaincode - List installed` + +Example: + +``` +Executing task: docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab peer lifecycle chaincode queryinstalled + +Installed chaincodes on peer: +Package ID: asset_1.0.0:65584e9a39a9b57053db44c30e1b20f727e4c9798effc5dc69c2e4530954f703, Label: asset_1.0.0 +``` + +## List Commited Chaincode + +Committed chaincodes can be shown by running `Terminal -> Run Task -> Chaincode - List Committed` + +Example: + +``` +Executing task: docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab peer lifecycle chaincode querycommitted -C channel1 + +Committed chaincode definitions on channel 'channel1': +Name: asset, Version: 1.0.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc +``` + +## Peer Admin Shell + +A peer admin shell with necessary environment varibles and certificates launched by running `Terminal -> Run Task -> Fabric - Peer Admin Shell` + +Example: + +``` +Executing task: docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID --workdir=/working microfab bash + +microfab@ea46ace0571b:/working$ +``` + +Show the working directory contents: + +``` +microfab@ea46ace0571b:/working$ ls +_chaincode_src _gateways _msp _packaged _utils _wallets +microfab@ea46ace0571b:/working$ +``` + +#### List channels the peer has joined: + +``` +microfab@ea46ace0571b:/working$ peer channel list +2024-06-11 15:47:02.805 UTC 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized +Channels peers has joined: +channel1 +``` + +#### List channels committed chaincode for the peer and channel: + +``` +Executing task: docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab peer lifecycle chaincode querycommitted -C channel1 + +Committed chaincode definitions on channel 'channel1': +Name: asset, Version: 1.0.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc +Name: asset-transfer-basic-go, Version: 1.0.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc +``` + +#### Invoke chaincode + +This example assumes you have built and deployed the fabric sample, asset-transfer-basic: + +peer chaincode invoke -o orderer-api.127-0-0-1.nip.io:8080 -C channel1 -n asset-transfer-basic-go -c '{"Args":["CreateAsset","1","blue","35","tom","1000"]}' --waitForEvent + +``` +microfab@ea46ace0571b:/working$ peer chaincode invoke -o orderer-api.127-0-0-1.nip.io:8080 -C channel1 -n asset-transfer-basic-go -c '{"Args":["CreateAsset","1","blue","35","tom","1000"]}' --waitForEvent +2024-06-11 17:19:32.237 UTC 0001 INFO [chaincodeCmd] ClientWait -> txid [9b3bbfd69e3217800aa5f94f1a6479e19c990c6ea13847d027317e3ee4dd5bd3] committed with status (VALID) at org1peer-api.127-0-0-1.nip.io:8080 +2024-06-11 17:19:32.240 UTC 0002 INFO [chaincodeCmd] chaincodeInvokeOrQuery -> Chaincode invoke successful. result: status:200 +``` + +#### Query chaincode + +peer chaincode query -C channel1 -n asset-transfer-basic-go -c '{"Args":["ReadAsset","1"]}' + +``` +microfab@ea46ace0571b:/working$ peer chaincode query -C channel1 -n asset -c '{"Args":["ReadAsset","1"]}' +{"AppraisedValue":1000,"Color":"blue","ID":"1","Owner":"tom","Size":35} +``` \ No newline at end of file diff --git a/examples/vscode_tasks/_utils/ccutils.sh b/examples/vscode_tasks/_utils/ccutils.sh new file mode 100644 index 0000000..9cc07f6 --- /dev/null +++ b/examples/vscode_tasks/_utils/ccutils.sh @@ -0,0 +1,340 @@ +#!/bin/bash + +verifyResult() { + if [ $1 -ne 0 ]; then + fatalln "$2" + fi +} + +# installChaincode PEER ORG +function installChaincode() { + set -x + res=1 + peer lifecycle chaincode queryinstalled --output json | jq -r 'try (.installed_chaincodes[].package_id)' | grep ^${PACKAGE_ID}$ >&/working/_utils/log.txt + if test $? -ne 0; then + peer lifecycle chaincode install /working/_packaged/${CHAINCODE_PACKAGE} >&/working/_utils/log.txt + res=$? + fi + { set +x; } 2>/dev/null + cat /working/_utils/log.txt + verifyResult $res "Chaincode installation on org1peer has failed" + successln "Chaincode is installed on org1peer" +} + +# queryInstalled PEER ORG +function queryInstalled() { + set -x + peer lifecycle chaincode queryinstalled --output json | jq -r 'try (.installed_chaincodes[].package_id)' | grep ^${PACKAGE_ID}$ >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + cat /working/_utils/log.txt + verifyResult $res "Query installed on org1peer has failed" + successln "Query installed successful on org1peer on channel" +} + +# approveForMyOrg VERSION PEER ORG +function approveForMyOrg() { + set -x + peer lifecycle chaincode approveformyorg -o orderer-api.127-0-0-1.nip.io:8080 --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --package-id ${PACKAGE_ID} --sequence ${CC_SEQUENCE} >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + cat /working/_utils/log.txt + verifyResult $res "Chaincode definition approved on org1peer on channel '$CHANNEL_NAME' failed" + successln "Chaincode definition approved on org1peer on channel '$CHANNEL_NAME'" +} + +# checkCommitReadiness VERSION PEER ORG +function checkCommitReadiness() { + infoln "Checking the commit readiness of the chaincode definition on org1peer on channel '$CHANNEL_NAME'..." + local rc=1 + local COUNTER=1 + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + sleep $DELAY + infoln "Attempting to check the commit readiness of the chaincode definition on org1peer, Retry after $DELAY seconds." + set -x + peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} --output json >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + let rc=0 + for var in "$@"; do + grep "$var" /working/_utils/log.txt &>/dev/null || let rc=1 + done + COUNTER=$(expr $COUNTER + 1) + done + cat /working/_utils/log.txt + if test $rc -eq 0; then + infoln "Checking the commit readiness of the chaincode definition successful on org1peer on channel '$CHANNEL_NAME'" + else + fatalln "After $MAX_RETRY attempts, Check commit readiness result on org1peer is INVALID!" + fi +} + +# commitChaincodeDefinition VERSION PEER ORG (PEER ORG)... +function commitChaincodeDefinition() { + + # while 'peer chaincode' command can get the orderer endpoint from the + # peer (if join was successful), let's supply it directly as we know + # it using the "-o" option + set -x + peer lifecycle chaincode commit -o orderer-api.127-0-0-1.nip.io:8080 --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + cat /working/_utils/log.txt + verifyResult $res "Chaincode definition commit failed on peer0.org${ORG} on channel '$CHANNEL_NAME' failed" + successln "Chaincode definition committed on channel '$CHANNEL_NAME'" +} + +# queryCommitted ORG +function queryCommitted() { + + EXPECTED_RESULT="Version: ${CC_VERSION}, Sequence: ${CC_SEQUENCE}, Endorsement Plugin: escc, Validation Plugin: vscc" + infoln "Querying chaincode definition on org1peer on channel '$CHANNEL_NAME'..." + local rc=1 + local COUNTER=1 + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + sleep $DELAY + infoln "Attempting to Query committed status on org1peer, Retry after $DELAY seconds." + set -x + peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name ${CC_NAME} >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + test $res -eq 0 && VALUE=$(cat /working/_utils/log.txt | grep -o '^Version: '$CC_VERSION', Sequence: [0-9]*, Endorsement Plugin: escc, Validation Plugin: vscc') + test "$VALUE" = "$EXPECTED_RESULT" && let rc=0 + COUNTER=$(expr $COUNTER + 1) + done + cat /working/_utils/log.txt + if test $rc -eq 0; then + successln "Query chaincode definition successful on org1peer on channel '$CHANNEL_NAME'" + else + fatalln "After $MAX_RETRY attempts, Query chaincode definition result on org1peer is INVALID!" + fi +} + +function chaincodeInvokeInit() { + parsePeerConnectionParameters $@ + res=$? + verifyResult $res "Invoke transaction failed on channel '$CHANNEL_NAME' due to uneven number of peer and org parameters " + + local rc=1 + local COUNTER=1 + local fcn_call='{"function":"'${CC_INIT_FCN}'","Args":[]}' + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + sleep $DELAY + # while 'peer chaincode' command can get the orderer endpoint from the + # peer (if join was successful), let's supply it directly as we know + # it using the "-o" option + set -x + infoln "invoke fcn call:${fcn_call}" + peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" -C $CHANNEL_NAME -n ${CC_NAME} "${PEER_CONN_PARMS[@]}" --isInit -c ${fcn_call} >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + cat /working/_utils/log.txt + verifyResult $res "Invoke execution on $PEERS failed " + successln "Invoke transaction successful on $PEERS on channel '$CHANNEL_NAME'" +} + +function chaincodeQuery() { + ORG=$1 + setGlobals $ORG + infoln "Querying on peer0.org${ORG} on channel '$CHANNEL_NAME'..." + local rc=1 + local COUNTER=1 + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + sleep $DELAY + infoln "Attempting to Query peer0.org${ORG}, Retry after $DELAY seconds." + set -x + peer chaincode query -C $CHANNEL_NAME -n ${CC_NAME} -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + cat /working/_utils/log.txt + if test $rc -eq 0; then + successln "Query successful on peer0.org${ORG} on channel '$CHANNEL_NAME'" + else + fatalln "After $MAX_RETRY attempts, Query result on peer0.org${ORG} is INVALID!" + fi +} + +function resolveSequence() { + + #if the sequence is not "auto", then use the provided sequence + if [[ "${CC_SEQUENCE}" != "auto" ]]; then + return 0 + fi + + local rc=1 + local COUNTER=1 + # first, find the sequence number of the committed chaincode + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + set -x + COMMITTED_CC_SEQUENCE=$(peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name ${CC_NAME} | sed -n "/Version:/{s/.*Sequence: //; s/, Endorsement Plugin:.*$//; p;}") + res=$? + { set +x; } 2>/dev/null + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + + # if there are no committed versions, then set the sequence to 1 + if [ -z $COMMITTED_CC_SEQUENCE ]; then + CC_SEQUENCE=1 + return 0 + fi + + rc=1 + COUNTER=1 + # next, find the sequence number of the approved chaincode + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + set -x + APPROVED_CC_SEQUENCE=$(peer lifecycle chaincode queryapproved --channelID $CHANNEL_NAME --name ${CC_NAME} | sed -n "/sequence:/{s/^sequence: //; s/, version:.*$//; p;}") + res=$? + { set +x; } 2>/dev/null + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + + # if the committed sequence and the approved sequence match, then increment the sequence + # otherwise, use the approved sequence + if [ $COMMITTED_CC_SEQUENCE == $APPROVED_CC_SEQUENCE ]; then + CC_SEQUENCE=$((COMMITTED_CC_SEQUENCE+1)) + else + CC_SEQUENCE=$APPROVED_CC_SEQUENCE + fi + +} + +#. scripts/envVar.sh + +queryInstalledOnPeer() { + + local rc=1 + local COUNTER=1 + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + #sleep $DELAY + #infoln "Attempting to list on peer0.org${ORG}, Retry after $DELAY seconds." + peer lifecycle chaincode queryinstalled >&/working/_utils/log.txt + res=$? + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + cat /working/_utils/log.txt +} + +queryCommittedOnChannel() { + CHANNEL=$1 + local rc=1 + local COUNTER=1 + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + #sleep $DELAY + #infoln "Attempting to list on peer0.org${ORG}, Retry after $DELAY seconds." + peer lifecycle chaincode querycommitted -C $CHANNEL >&/working/_utils/log.txt + res=$? + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + cat /working/_utils/log.txt + if test $rc -ne 0; then + fatalln "After $MAX_RETRY attempts, Failed to retrieve committed chaincode!" + fi + +} + +## Function to list chaincodes installed on the peer and committed chaincode visible to the org +listAllCommitted() { + + local rc=1 + local COUNTER=1 + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + CHANNEL_LIST=$(peer channel list | sed '1,1d') + res=$? + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + if test $rc -eq 0; then + for channel in $CHANNEL_LIST + do + queryCommittedOnChannel "$channel" + done + else + fatalln "After $MAX_RETRY attempts, Failed to retrieve committed chaincode!" + fi + +} + +chaincodeInvoke() { + ORG=$1 + CHANNEL=$2 + CC_NAME=$3 + CC_INVOKE_CONSTRUCTOR=$4 + + infoln "Invoking on peer0.org${ORG} on channel '$CHANNEL_NAME'..." + local rc=1 + local COUNTER=1 + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + sleep $DELAY + infoln "Attempting to Invoke on peer0.org${ORG}, Retry after $DELAY seconds." + set -x + peer chaincode invoke -o localhost:7050 -C $CHANNEL_NAME -n ${CC_NAME} -c ${CC_INVOKE_CONSTRUCTOR} --tls --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $PEER0_ORG1_CA --peerAddresses localhost:9051 --tlsRootCertFiles $PEER0_ORG2_CA >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + cat /working/_utils/log.txt + if test $rc -eq 0; then + successln "Invoke successful on peer0.org${ORG} on channel '$CHANNEL_NAME'" + else + fatalln "After $MAX_RETRY attempts, Invoke result on peer0.org${ORG} is INVALID!" + fi +} + +chaincodeQuery() { + ORG=$1 + CHANNEL=$2 + CC_NAME=$3 + CC_QUERY_CONSTRUCTOR=$4 + + infoln "Querying on peer0.org${ORG} on channel '$CHANNEL_NAME'..." + local rc=1 + local COUNTER=1 + # continue to poll + # we either get a successful response, or reach MAX RETRY + while [ $rc -ne 0 -a $COUNTER -lt $MAX_RETRY ]; do + sleep $DELAY + infoln "Attempting to Query peer0.org${ORG}, Retry after $DELAY seconds." + set -x + peer chaincode query -C $CHANNEL_NAME -n ${CC_NAME} -c ${CC_QUERY_CONSTRUCTOR} >&/working/_utils/log.txt + res=$? + { set +x; } 2>/dev/null + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + cat /working/_utils/log.txt + if test $rc -eq 0; then + successln "Query successful on peer0.org${ORG} on channel '$CHANNEL_NAME'" + else + fatalln "After $MAX_RETRY attempts, Query result on peer0.org${ORG} is INVALID!" + fi +} \ No newline at end of file diff --git a/examples/vscode_tasks/_utils/deployCC.sh b/examples/vscode_tasks/_utils/deployCC.sh new file mode 100755 index 0000000..fed05b1 --- /dev/null +++ b/examples/vscode_tasks/_utils/deployCC.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +source /working/_utils/utils.sh + +CHANNEL_NAME="channel1" +CHAINCODE_PACKAGE=${1} +MAX_RETRY="5" +DELAY="3" +CC_SEQUENCE="auto" + +println "executing with the following" +println "- CHANNEL_NAME: ${C_GREEN}${CHANNEL_NAME}${C_RESET}" +println "- CHAINCODE_PACKAGE: ${C_GREEN}${CHAINCODE_PACKAGE}${C_RESET}" + +. /working/_utils/ccutils.sh + +function checkPrereqs() { + jq --version > /dev/null 2>&1 + + if [[ $? -ne 0 ]]; then + errorln "jq command not found..." + errorln + errorln "Follow the instructions in the Fabric docs to install the prereqs" + errorln "https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html" + exit 1 + fi +} + +#check for prerequisites +checkPrereqs + +PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid /working/_packaged/${CHAINCODE_PACKAGE}) + +infoln "Chaincode package ID: ${PACKAGE_ID}" + +export CC_NAME=${CHAINCODE_PACKAGE%_*} +export CC_VERSION=$(echo ${CHAINCODE_PACKAGE} | sed 's/.tar.gz//g' | sed 's/.*_//') + +infoln "Chaincode Name: ${CC_NAME}" +infoln "Chaincode Version: ${CC_VERSION}" + +## Install chaincode on peer0.org1 and peer0.org2 +infoln "Installing chaincode on org1peer..." +installChaincode + +## Set the sequence +resolveSequence + +infoln "Using sequence ${CC_SEQUENCE}" + +## query whether the chaincode is installed +queryInstalled + +## approve the definition for org1 +approveForMyOrg + +## check whether the chaincode definition is ready to be committed +## expect org1 to have approved and org2 not to +checkCommitReadiness "\"Org1MSP\": true" + +## now that we know for sure both orgs have approved, commit the definition +commitChaincodeDefinition + +## query on both orgs to see that the definition committed successfully +queryCommitted + +exit 0 diff --git a/examples/vscode_tasks/_utils/package.sh b/examples/vscode_tasks/_utils/package.sh new file mode 100755 index 0000000..6e5ebf3 --- /dev/null +++ b/examples/vscode_tasks/_utils/package.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +CHAINCODE_NAME=${1} +CHAINCODE_VERSION=${2} +CHAINCODE_LANGUAGE=${3} +PACKAGE_TYPE=${4} +CHAINCODE_PATH=${5} + +NOTPASSED="" + +if [ -z "${CHAINCODE_NAME}" ];then + NOTPASSED="${NOTPASSED} CHAINCODE_NAME" +fi + +if [ -z "${CHAINCODE_VERSION}" ];then + NOTPASSED="${NOTPASSED} CHAINCODE_VERSION" +fi + +if [ -z "${CHAINCODE_LANGUAGE}" ];then + NOTPASSED="${NOTPASSED} CHAINCODE_LANGUAGE" +fi + +if [ -z "${PACKAGE_TYPE}" ];then + NOTPASSED="${NOTPASSED} PACKAGE_TYPE" +fi + +if [ -z "${CHAINCODE_PATH}" ];then + NOTPASSED="${NOTPASSED} CHAINCODE_PATH" +fi + +if [ ! -z "${NOTPASSED}" ]; then + echo "${NOTPASSED} not passed" + echo "" + echo "Usage: ./package.sh " + echo "" + echo "CHAINCODE_NAME - chaincode name for the packaged chaincode" + echo "CHAINCODE_VERSION - chaincode version for the packaged chaincode" + echo "CHAINCODE_LANGUAGE - chaincode language (golang, node or java)" + echo "PACKAGE_TYPE - chaincode packaging type (cds or tar)" + echo "CHAINCODE_PATH - path to the chaincode source (fully qualfied path)" + echo "" + echo "Examples:" + echo "" + echo "Pacakging for cds file:" + echo "./package.sh marbles02 1.1.2 node cds /Users/dev/fabric/chaincode/chaincode/marbles02/javascript" + echo "" + echo "Pacakging for tar file:" + echo "./package.sh marbles02 3.0.0 golang tar /Users/dev/support/chaincode/marbles02/go" + echo "" + exit 1 +fi + +if ! [[ ${CHAINCODE_LANGUAGE} == "node" || ${CHAINCODE_LANGUAGE} == "golang" || ${CHAINCODE_LANGUAGE} == "java" ]]; then + echo "Chaincode language must be node, golang or java" + exit 1 +fi + +if ! [[ ${PACKAGE_TYPE} == "cds" || ${PACKAGE_TYPE} == "tar" ]]; then + echo "Package type must be cds or tar" + exit 1 +fi + +export FABRIC_CFG_PATH=/etc/hyperledger/fabric +export CORE_PEER_MSPCONFIGPATH=/working/_msp/Org1/org1admin/msp + +if [[ ("${PACKAGE_TYPE}" == "cds") ]]; then + echo "Building chaincode package ${CHAINCODE_NAME}@${CHAINCODE_VERSION}.cds" + peer chaincode package /working/_packaged/${CHAINCODE_NAME}@${CHAINCODE_VERSION}.cds --path ${CHAINCODE_PATH} --lang ${CHAINCODE_LANGUAGE} -n ${CHAINCODE_NAME} -v ${CHAINCODE_VERSION} +else + echo "Building chaincode package ${CHAINCODE_NAME}_${CHAINCODE_VERSION}.tar" + peer lifecycle chaincode package /working/_packaged/${CHAINCODE_NAME}_${CHAINCODE_VERSION}.tar.gz --path ${CHAINCODE_PATH} --lang ${CHAINCODE_LANGUAGE} --label ${CHAINCODE_NAME}_${CHAINCODE_VERSION} +fi + +echo "Complete" + diff --git a/examples/vscode_tasks/_utils/tasks.json b/examples/vscode_tasks/_utils/tasks.json new file mode 100644 index 0000000..299d853 --- /dev/null +++ b/examples/vscode_tasks/_utils/tasks.json @@ -0,0 +1,123 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "options": { + "env": { + "local_directory": "/Users/celder/SupportOffering/testit", + "CORE_PEER_MSPCONFIGPATH": "/working/_msp/Org1/org1admin/msp", + "CORE_PEER_ADDRESS": "org1peer-api.127-0-0-1.nip.io:8080", + "CORE_PEER_LOCALMSPID": "Org1MSP" + } + }, + "tasks": [ + { + "label": "Chaincode - List built chaincode packages", + "type": "shell", + "command": "cd $local_directory && ls _packaged/", + "problemMatcher": [] + }, + { + "label": "Fabric - Start", + "type": "shell", + "command": "docker run -d --rm -p 8080:8080 -u microfab -v $local_directory:/working --name microfab microfab:latest && sleep 8 && cd $local_directory && docker cp microfab:opt/examples/vscode_tasks/_utils $local_directory/_utils && curl -s http://console.127-0-0-1.nip.io:8080/ak/api/v1/components | npx @hyperledger-labs/weft microfab -w _wallets -p _gateways -m _msp -f", + "problemMatcher": [] + }, + { + "label": "Fabric - Stop", + "type": "shell", + "command": "docker stop microfab", + "problemMatcher": [] + }, + { + "label": "Fabric - Show Logs", + "type": "shell", + "command": "docker logs microfab -f", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "new", + "showReuseMessage": true, + "clear": false + }, + "problemMatcher": [] + }, + { + "label": "Fabric - Peer Admin Shell ", + "type": "shell", + "command": "docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab bash && cd /working", + "problemMatcher": [] + }, + { + "label": "Chaincode - Package open project", + "type": "shell", + "command": "cd $local_directory && rm -rf _chaincode_src && mkdir -p _chaincode_src && mkdir -p _packaged && cp -R ${workspaceFolder} _chaincode_src/temp && docker exec -it microfab /working/_utils/package.sh ${input:chaincodeName} ${input:chaincodeVersion} ${input:language} ${input:chaincodeType} /working/_chaincode_src/temp", + "problemMatcher": [] + }, + { + "label": "Chaincode - List Committed", + "type": "shell", + "command": "docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab peer lifecycle chaincode querycommitted -C channel1", + "problemMatcher": [] + }, + { + "label": "Chaincode - List Installed ", + "type": "shell", + "command": "docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab peer lifecycle chaincode queryinstalled", + "problemMatcher": [] + }, + { + "label": "Chaincode - Deploy", + "type": "shell", + "command": "docker exec -it -e CORE_PEER_MSPCONFIGPATH=$CORE_PEER_MSPCONFIGPATH -e CORE_PEER_ADDRESS=$CORE_PEER_ADDRESS -e CORE_PEER_LOCALMSPID=$CORE_PEER_LOCALMSPID microfab /working/_utils/deployCC.sh ${input:openDialog}", + "problemMatcher": [] + } + ], + "inputs": [ + { + "type": "pickString", + "id": "language", + "description": "Chaincode language", + "options": [ + "golang", + "node", + "java" + ], + "default": "golang" + }, + { + "type": "pickString", + "id": "chaincodeType", + "description": "Chaincode Type", + "options": [ + "tar", + "cds" + ], + "default": "tar" + }, + { + "type": "promptString", + "id": "chaincodeName", + "description": "Enter the name of the chaincode" + }, + { + "type": "promptString", + "id": "chaincodeVersion", + "description": "Enter the version of the chaincode" + }, + { + "id": "openDialog", + "type": "command", + "command": "extension.commandvariable.file.openDialog", + "args": { + "canSelect": "files", + "defaultUri": "/Users/celder/SupportOffering/testit", + "transform": { + "text": "${fileBasename}" + }, + } + } + ] +} + diff --git a/examples/vscode_tasks/_utils/utils.sh b/examples/vscode_tasks/_utils/utils.sh new file mode 100755 index 0000000..68ab4f4 --- /dev/null +++ b/examples/vscode_tasks/_utils/utils.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +C_RESET='\033[0m' +C_RED='\033[0;31m' +C_GREEN='\033[0;32m' +C_BLUE='\033[0;34m' +C_YELLOW='\033[1;33m' + +function installPrereqs() { + + infoln "installing prereqs" + + FILE=../install-fabric.sh + if [ ! -f $FILE ]; then + curl -sSLO https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh && chmod +x install-fabric.sh + cp install-fabric.sh .. + fi + + IMAGE_PARAMETER="" + if [ "$IMAGETAG" != "default" ]; then + IMAGE_PARAMETER="-f ${IMAGETAG}" + fi + + CA_IMAGE_PARAMETER="" + if [ "$CA_IMAGETAG" != "default" ]; then + CA_IMAGE_PARAMETER="-c ${CA_IMAGETAG}" + fi + + cd .. + ./install-fabric.sh ${IMAGE_PARAMETER} ${CA_IMAGE_PARAMETER} docker binary + +} + +# println echos string +function println() { + echo -e "$1" +} + +# errorln echos i red color +function errorln() { + println "${C_RED}${1}${C_RESET}" +} + +# successln echos in green color +function successln() { + println "${C_GREEN}${1}${C_RESET}" +} + +# infoln echos in blue color +function infoln() { + println "${C_BLUE}${1}${C_RESET}" +} + +# warnln echos in yellow color +function warnln() { + println "${C_YELLOW}${1}${C_RESET}" +} + +# fatalln echos in red color and exits with fail status +function fatalln() { + errorln "$1" + exit 1 +} + +export -f errorln +export -f successln +export -f infoln +export -f warnln diff --git a/examples/vscode_tasks/images/ChaincodeLanguage.png b/examples/vscode_tasks/images/ChaincodeLanguage.png new file mode 100644 index 0000000..29c0191 Binary files /dev/null and b/examples/vscode_tasks/images/ChaincodeLanguage.png differ diff --git a/examples/vscode_tasks/images/ChaincodeName.png b/examples/vscode_tasks/images/ChaincodeName.png new file mode 100644 index 0000000..66b85a0 Binary files /dev/null and b/examples/vscode_tasks/images/ChaincodeName.png differ diff --git a/examples/vscode_tasks/images/ChaincodeProject.png b/examples/vscode_tasks/images/ChaincodeProject.png new file mode 100644 index 0000000..b9c636c Binary files /dev/null and b/examples/vscode_tasks/images/ChaincodeProject.png differ diff --git a/examples/vscode_tasks/images/ChaincodeTasks.png b/examples/vscode_tasks/images/ChaincodeTasks.png new file mode 100644 index 0000000..a055e56 Binary files /dev/null and b/examples/vscode_tasks/images/ChaincodeTasks.png differ diff --git a/examples/vscode_tasks/images/ChaincodeType.png b/examples/vscode_tasks/images/ChaincodeType.png new file mode 100644 index 0000000..2ccfc46 Binary files /dev/null and b/examples/vscode_tasks/images/ChaincodeType.png differ diff --git a/examples/vscode_tasks/images/ChaincodeVersion.png b/examples/vscode_tasks/images/ChaincodeVersion.png new file mode 100644 index 0000000..d32a9cd Binary files /dev/null and b/examples/vscode_tasks/images/ChaincodeVersion.png differ diff --git a/examples/vscode_tasks/images/DeployChaincode.png b/examples/vscode_tasks/images/DeployChaincode.png new file mode 100644 index 0000000..27d2a3b Binary files /dev/null and b/examples/vscode_tasks/images/DeployChaincode.png differ diff --git a/examples/vscode_tasks/images/RunFabric.png b/examples/vscode_tasks/images/RunFabric.png new file mode 100644 index 0000000..0c78a56 Binary files /dev/null and b/examples/vscode_tasks/images/RunFabric.png differ diff --git a/examples/vscode_tasks/images/RunTask.png b/examples/vscode_tasks/images/RunTask.png new file mode 100644 index 0000000..9018314 Binary files /dev/null and b/examples/vscode_tasks/images/RunTask.png differ