From 53f0ef0d9239dc0277374d8880e766fe97e59222 Mon Sep 17 00:00:00 2001 From: fraVlaca <86831094+fraVlaca@users.noreply.github.com> Date: Mon, 6 Sep 2021 13:47:25 +0100 Subject: [PATCH 001/106] updated chaincodes for asset-transfer-basic in order to show good example on how achieving determinism over json (#486) * updated chaincodes for asset-trnsfer-basic in order to show good example on how achieving determinism in json Signed-off-by: fraVlaca * final fixes for chaincode-java of asset-tranfer-basic Signed-off-by: fraVlaca * removed extra unused excheptions Signed-off-by: fraVlaca * corrected indentation of contract in the chancode-javasript of asset-trnsfer-basic Signed-off-by: fraVlaca * last fixes for chaincode-javascript of asset-transfer-basic Signed-off-by: fraVlaca * last last fixes for chaincode-javascript of asset-transfer-basic Signed-off-by: fraVlaca --- .../chaincode-go/chaincode/smartcontract.go | 10 +++++---- .../samples/assettransfer/AssetTransfer.java | 19 ++++++++++------- .../chaincode-javascript/lib/assetTransfer.js | 21 +++++++++++++------ .../chaincode-javascript/package.json | 4 +++- .../chaincode-typescript/package.json | 4 +++- .../chaincode-typescript/src/assetTransfer.ts | 21 +++++++++++++------ 6 files changed, 53 insertions(+), 26 deletions(-) diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go index 71e8dd84..7373ad42 100644 --- a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go +++ b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go @@ -13,12 +13,14 @@ type SmartContract struct { } // Asset describes basic details of what makes up a simple asset +//Insert struct field in alphabetic order => to achieve determinism accross languages +// golang keeps the order when marshal to json but doesn't order automatically type Asset struct { + AppraisedValue int `json:"AppraisedValue"` + Color string `json:"Color"` ID string `json:"ID"` - Color string `json:"color"` - Size int `json:"size"` - Owner string `json:"owner"` - AppraisedValue int `json:"appraisedValue"` + Owner string `json:"Owner"` + Size int `json:"Size"` } // InitLedger adds a base set of assets to the ledger diff --git a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java b/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java index 465d4694..fa7aba67 100644 --- a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java +++ b/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java @@ -7,6 +7,7 @@ package org.hyperledger.fabric.samples.assettransfer; import java.util.ArrayList; import java.util.List; + import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.annotation.Contact; @@ -86,8 +87,9 @@ public final class AssetTransfer implements ContractInterface { } Asset asset = new Asset(assetID, color, size, owner, appraisedValue); - String assetJSON = genson.serialize(asset); - stub.putStringState(assetID, assetJSON); + //Use Genson to convert the Asset into string, sort it alphabetically and serialize it into a json string + String sortedJson = genson.serialize(asset); + stub.putStringState(assetID, sortedJson); return asset; } @@ -137,9 +139,9 @@ public final class AssetTransfer implements ContractInterface { } Asset newAsset = new Asset(assetID, color, size, owner, appraisedValue); - String newAssetJSON = genson.serialize(newAsset); - stub.putStringState(assetID, newAssetJSON); - + //Use Genson to convert the Asset into string, sort it alphabetically and serialize it into a json string + String sortedJson = genson.serialize(newAsset); + stub.putStringState(assetID, sortedJson); return newAsset; } @@ -199,8 +201,9 @@ public final class AssetTransfer implements ContractInterface { Asset asset = genson.deserialize(assetJSON, Asset.class); Asset newAsset = new Asset(asset.getAssetID(), asset.getColor(), asset.getSize(), newOwner, asset.getAppraisedValue()); - String newAssetJSON = genson.serialize(newAsset); - stub.putStringState(assetID, newAssetJSON); + //Use a Genson to conver the Asset into string, sort it alphabetically and serialize it into a json string + String sortedJson = genson.serialize(newAsset); + stub.putStringState(assetID, sortedJson); return newAsset; } @@ -225,8 +228,8 @@ public final class AssetTransfer implements ContractInterface { for (KeyValue result: results) { Asset asset = genson.deserialize(result.getStringValue(), Asset.class); + System.out.println(asset); queryResults.add(asset); - System.out.println(asset.toString()); } final String response = genson.serialize(queryResults); diff --git a/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js b/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js index a1a27aa4..22d109c8 100644 --- a/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js +++ b/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js @@ -6,6 +6,9 @@ 'use strict'; +// Deterministic JSON.stringify() +const stringify = require('json-stringify-deterministic'); +const sortKeysRecursive = require('sort-keys-recursive'); const { Contract } = require('fabric-contract-api'); class AssetTransfer extends Contract { @@ -58,8 +61,11 @@ class AssetTransfer extends Contract { for (const asset of assets) { asset.docType = 'asset'; - await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset))); - console.info(`Asset ${asset.ID} initialized`); + // example of how to write to world state deterministically + // use convetion of alphabetic order + // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + // when retrieving data, in any lang, the order of data will be the same and consequently also the corresonding hash + await ctx.stub.putState(asset.ID, Buffer.from(stringify(sortKeysRecursive(asset)))); } } @@ -77,7 +83,8 @@ class AssetTransfer extends Contract { Owner: owner, AppraisedValue: appraisedValue, }; - await ctx.stub.putState(id, Buffer.from(JSON.stringify(asset))); + //we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); return JSON.stringify(asset); } @@ -105,7 +112,8 @@ class AssetTransfer extends Contract { Owner: owner, AppraisedValue: appraisedValue, }; - return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset))); + // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(updatedAsset)))); } // DeleteAsset deletes an given asset from the world state. @@ -128,7 +136,8 @@ class AssetTransfer extends Contract { const assetString = await this.ReadAsset(ctx, id); const asset = JSON.parse(assetString); asset.Owner = newOwner; - return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset))); + // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); } // GetAllAssets returns all assets found in the world state. @@ -146,7 +155,7 @@ class AssetTransfer extends Contract { console.log(err); record = strValue; } - allResults.push({ Key: result.value.key, Record: record }); + allResults.push(record); result = await iterator.next(); } return JSON.stringify(allResults); diff --git a/asset-transfer-basic/chaincode-javascript/package.json b/asset-transfer-basic/chaincode-javascript/package.json index 9cc22242..430f9f61 100644 --- a/asset-transfer-basic/chaincode-javascript/package.json +++ b/asset-transfer-basic/chaincode-javascript/package.json @@ -18,7 +18,9 @@ "license": "Apache-2.0", "dependencies": { "fabric-contract-api": "^2.0.0", - "fabric-shim": "^2.0.0" + "fabric-shim": "^2.0.0", + "json-stringify-deterministic": "^1.0.1", + "sort-keys-recursive": "^2.0.0" }, "devDependencies": { "chai": "^4.1.2", diff --git a/asset-transfer-basic/chaincode-typescript/package.json b/asset-transfer-basic/chaincode-typescript/package.json index 2b681fc1..befe4a5f 100644 --- a/asset-transfer-basic/chaincode-typescript/package.json +++ b/asset-transfer-basic/chaincode-typescript/package.json @@ -22,7 +22,9 @@ "license": "Apache-2.0", "dependencies": { "fabric-contract-api": "^2.0.0", - "fabric-shim": "^2.0.0" + "fabric-shim": "^2.0.0", + "json-stringify-deterministic":"^1.0.0", + "sort-keys-recursive":"^2.0.0" }, "devDependencies": { "@types/chai": "^4.1.7", diff --git a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts index 55b19b77..db2f9a9e 100644 --- a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts +++ b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts @@ -1,7 +1,9 @@ /* * SPDX-License-Identifier: Apache-2.0 */ - +// Deterministic JSON.stringify() +import * as stringify from 'json-stringify-deterministic'; +import * as sortKeysRecursive from 'sort-keys-recursive'; import {Context, Contract, Info, Returns, Transaction} from 'fabric-contract-api'; import {Asset} from './asset'; @@ -57,7 +59,11 @@ export class AssetTransferContract extends Contract { for (const asset of assets) { asset.docType = 'asset'; - await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset))); + // example of how to write to world state deterministically + // use convetion of alphabetic order + // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + // when retrieving data, in any lang, the order of data will be the same and consequently also the corresonding hash + await ctx.stub.putState(asset.ID, Buffer.from(stringify(sortKeysRecursive(asset)))); console.info(`Asset ${asset.ID} initialized`); } } @@ -77,7 +83,8 @@ export class AssetTransferContract extends Contract { Owner: owner, AppraisedValue: appraisedValue, }; - await ctx.stub.putState(id, Buffer.from(JSON.stringify(asset))); + // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); } // ReadAsset returns the asset stored in the world state with given id. @@ -106,7 +113,8 @@ export class AssetTransferContract extends Contract { Owner: owner, AppraisedValue: appraisedValue, }; - return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset))); + // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(updatedAsset)))); } // DeleteAsset deletes an given asset from the world state. @@ -133,7 +141,8 @@ export class AssetTransferContract extends Contract { const assetString = await this.ReadAsset(ctx, id); const asset = JSON.parse(assetString); asset.Owner = newOwner; - await ctx.stub.putState(id, Buffer.from(JSON.stringify(asset))); + // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); } // GetAllAssets returns all assets found in the world state. @@ -153,7 +162,7 @@ export class AssetTransferContract extends Contract { console.log(err); record = strValue; } - allResults.push({Key: result.value.key, Record: record}); + allResults.push(record); result = await iterator.next(); } return JSON.stringify(allResults); From 38e08da13b1f84f4b31f603d0c0b1d10eb068970 Mon Sep 17 00:00:00 2001 From: nikhil550 Date: Tue, 7 Sep 2021 10:22:26 -0400 Subject: [PATCH 002/106] Rm docker files mount for CLI container (#479) Signed-off-by: Nikhil Gupta Co-authored-by: Nikhil Gupta Co-authored-by: Arnaud J Le Hors --- test-network/docker/docker-compose-test-net.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/test-network/docker/docker-compose-test-net.yaml b/test-network/docker/docker-compose-test-net.yaml index 86fc85bf..c070f82e 100644 --- a/test-network/docker/docker-compose-test-net.yaml +++ b/test-network/docker/docker-compose-test-net.yaml @@ -151,7 +151,6 @@ services: working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: /bin/bash volumes: - - /var/run/:/host/var/run/ - ../organizations:/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations - ../scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ depends_on: From a97c0b0359a14936a42baedab9e3f4e285895fb6 Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Wed, 8 Sep 2021 15:54:11 +0100 Subject: [PATCH 003/106] Add in a setEnvOrg script (#487) Helper script to set environment variables, so make it eaiser to use the peer command from the shell command line Signed-off-by: Matthew B White --- test-network/README.md | 19 +++++++++++++ test-network/setOrgEnv.sh | 59 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100755 test-network/setOrgEnv.sh diff --git a/test-network/README.md b/test-network/README.md index 418e467e..f861db94 100644 --- a/test-network/README.md +++ b/test-network/README.md @@ -3,3 +3,22 @@ You can use the `./network.sh` script to stand up a simple Fabric test network. The test network has two peer organizations with one peer each and a single node raft ordering service. You can also use the `./network.sh` script to create channels and deploy chaincode. For more information, see [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html). The test network is being introduced in Fabric v2.0 as the long term replacement for the `first-network` sample. Before you can deploy the test network, you need to follow the instructions to [Install the Samples, Binaries and Docker Images](https://hyperledger-fabric.readthedocs.io/en/latest/install.html) in the Hyperledger Fabric documentation. + +## Using the Peer commands +The `setOrgEnv.sh` script can be used to setup the environment variables for the ogrganziations, this will will help to be able to use the `peer` commands directly. + +First, ensure that the peer binaries are on your path, and the Fabric Config path is set Assuming that you're in the `test-network` directory. + +```bash + export PATH=$PATH:$(realpath ../bin) + export FABRIC_CFG_PATH=$(realpath ../config) +``` + +You can then set up the environment variables for each organization. The `./setOrgEnv.sh` command is designed to be run as follows. + +```bash +export $(./setOrgEnv.sh Org2 | xargs) +``` + +You will now be able to run the `peer` commands in the context of Org2. If a different command prompt you can run the same command with Org1 instead. +The `setOrgEnv` script outputs a series of `=` strings. These can then be fed into the export command for your current shell \ No newline at end of file diff --git a/test-network/setOrgEnv.sh b/test-network/setOrgEnv.sh new file mode 100755 index 00000000..b66074fb --- /dev/null +++ b/test-network/setOrgEnv.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# +# SPDX-License-Identifier: Apache-2.0 + + + + +# default to using Org1 +ORG=${1:-Org1} + +# Exit on first error, print all commands. +set -e +set -o pipefail + +# Where am I? +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" + +ORDERER_CA=${DIR}/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem +PEER0_ORG1_CA=${DIR}/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt +PEER0_ORG2_CA=${DIR}/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt +PEER0_ORG3_CA=${DIR}/test-network/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt + + +if [[ ${ORG,,} == "org1" || ${ORG,,} == "digibank" ]]; then + + CORE_PEER_LOCALMSPID=Org1MSP + CORE_PEER_MSPCONFIGPATH=${DIR}/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp + CORE_PEER_ADDRESS=localhost:7051 + CORE_PEER_TLS_ROOTCERT_FILE=${DIR}/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt + +elif [[ ${ORG,,} == "org2" || ${ORG,,} == "magnetocorp" ]]; then + + CORE_PEER_LOCALMSPID=Org2MSP + CORE_PEER_MSPCONFIGPATH=${DIR}/test-network/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp + CORE_PEER_ADDRESS=localhost:9051 + CORE_PEER_TLS_ROOTCERT_FILE=${DIR}/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt + +else + echo "Unknown \"$ORG\", please choose Org1/Digibank or Org2/Magnetocorp" + echo "For example to get the environment variables to set upa Org2 shell environment run: ./setOrgEnv.sh Org2" + echo + echo "This can be automated to set them as well with:" + echo + echo 'export $(./setOrgEnv.sh Org2 | xargs)' + exit 1 +fi + +# output the variables that need to be set +echo "CORE_PEER_TLS_ENABLED=true" +echo "ORDERER_CA=${ORDERER_CA}" +echo "PEER0_ORG1_CA=${PEER0_ORG1_CA}" +echo "PEER0_ORG2_CA=${PEER0_ORG2_CA}" +echo "PEER0_ORG3_CA=${PEER0_ORG3_CA}" + +echo "CORE_PEER_MSPCONFIGPATH=${CORE_PEER_MSPCONFIGPATH}" +echo "CORE_PEER_ADDRESS=${CORE_PEER_ADDRESS}" +echo "CORE_PEER_TLS_ROOTCERT_FILE=${CORE_PEER_TLS_ROOTCERT_FILE}" + +echo "CORE_PEER_LOCALMSPID=${CORE_PEER_LOCALMSPID}" \ No newline at end of file From 5860027ac82f21d896583fb9e3018ad3bae995b0 Mon Sep 17 00:00:00 2001 From: jkneubuh <86427252+jkneubuh@users.noreply.github.com> Date: Thu, 9 Sep 2021 09:04:07 -0400 Subject: [PATCH 004/106] kubernetes test network : initial commit (#471) * This is the initial add of a test-network-kind Signed-off-by: Josh Kneubuhl * Update the test-network-kind README; removes the local docker registry; updated 'clean' instructions Signed-off-by: Josh Kneubuhl Co-authored-by: Matthew B White --- .gitignore | 1 + test-network-kind/.gitignore | 2 + test-network-kind/README.md | 269 +++++++ test-network-kind/bin/make-kind-with-reg.sh | 31 + .../chaincode/asset-transfer-basic-debug.tgz | Bin 0 -> 416 bytes .../asset-transfer-basic-debug/code.tar.gz | Bin 0 -> 196 bytes .../connection.json | 5 + .../asset-transfer-basic-debug/metadata.json | 4 + .../chaincode/asset-transfer-basic.tgz | Bin 0 -> 411 bytes .../asset-transfer-basic/code.tar.gz | Bin 0 -> 195 bytes .../asset-transfer-basic/connection.json | 5 + .../asset-transfer-basic/metadata.json | 4 + test-network-kind/config/configtx.yaml | 389 +++++++++ test-network-kind/config/core.yaml | 759 ++++++++++++++++++ test-network-kind/config/crypto-config.yaml | 59 ++ test-network-kind/config/orderer.yaml | 420 ++++++++++ .../kube/cc-asset-transfer-basic.yaml | 46 ++ test-network-kind/kube/debug.yaml | 55 ++ .../kube/job-create-channel-config.yaml | 45 ++ test-network-kind/kube/job-crypto-config.yaml | 41 + .../kube/job-orderer-genesis.yaml | 44 + .../kube/job-scrub-fabric-volume.yaml | 32 + .../kube/job-update-org1-anchor-peers.yaml | 45 ++ .../kube/job-update-org2-anchor-peers.yaml | 45 ++ test-network-kind/kube/ns-test-network.yaml | 10 + test-network-kind/kube/orderer1.yaml | 87 ++ test-network-kind/kube/orderer2.yaml | 87 ++ test-network-kind/kube/orderer3.yaml | 87 ++ test-network-kind/kube/org1-peer1.yaml | 110 +++ test-network-kind/kube/org1-peer2.yaml | 105 +++ test-network-kind/kube/org2-peer1.yaml | 105 +++ test-network-kind/kube/org2-peer2.yaml | 105 +++ test-network-kind/kube/pv-fabric.yaml | 18 + test-network-kind/kube/pvc-fabric.yaml | 17 + 34 files changed, 3032 insertions(+) create mode 100644 test-network-kind/.gitignore create mode 100644 test-network-kind/README.md create mode 100755 test-network-kind/bin/make-kind-with-reg.sh create mode 100644 test-network-kind/chaincode/asset-transfer-basic-debug.tgz create mode 100644 test-network-kind/chaincode/asset-transfer-basic-debug/code.tar.gz create mode 100644 test-network-kind/chaincode/asset-transfer-basic-debug/connection.json create mode 100644 test-network-kind/chaincode/asset-transfer-basic-debug/metadata.json create mode 100644 test-network-kind/chaincode/asset-transfer-basic.tgz create mode 100644 test-network-kind/chaincode/asset-transfer-basic/code.tar.gz create mode 100644 test-network-kind/chaincode/asset-transfer-basic/connection.json create mode 100644 test-network-kind/chaincode/asset-transfer-basic/metadata.json create mode 100644 test-network-kind/config/configtx.yaml create mode 100644 test-network-kind/config/core.yaml create mode 100644 test-network-kind/config/crypto-config.yaml create mode 100644 test-network-kind/config/orderer.yaml create mode 100644 test-network-kind/kube/cc-asset-transfer-basic.yaml create mode 100644 test-network-kind/kube/debug.yaml create mode 100644 test-network-kind/kube/job-create-channel-config.yaml create mode 100644 test-network-kind/kube/job-crypto-config.yaml create mode 100644 test-network-kind/kube/job-orderer-genesis.yaml create mode 100644 test-network-kind/kube/job-scrub-fabric-volume.yaml create mode 100644 test-network-kind/kube/job-update-org1-anchor-peers.yaml create mode 100644 test-network-kind/kube/job-update-org2-anchor-peers.yaml create mode 100644 test-network-kind/kube/ns-test-network.yaml create mode 100644 test-network-kind/kube/orderer1.yaml create mode 100644 test-network-kind/kube/orderer2.yaml create mode 100644 test-network-kind/kube/orderer3.yaml create mode 100644 test-network-kind/kube/org1-peer1.yaml create mode 100644 test-network-kind/kube/org1-peer2.yaml create mode 100644 test-network-kind/kube/org2-peer1.yaml create mode 100644 test-network-kind/kube/org2-peer2.yaml create mode 100644 test-network-kind/kube/pv-fabric.yaml create mode 100644 test-network-kind/kube/pvc-fabric.yaml diff --git a/.gitignore b/.gitignore index e4f9fd48..63eb90ca 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ node_modules/ # Ignore Gradle build output directory build package-lock.json +external-chaincode/ diff --git a/test-network-kind/.gitignore b/test-network-kind/.gitignore new file mode 100644 index 00000000..ddef5d2a --- /dev/null +++ b/test-network-kind/.gitignore @@ -0,0 +1,2 @@ +crypto-config/ +channel-artifacts/ diff --git a/test-network-kind/README.md b/test-network-kind/README.md new file mode 100644 index 00000000..260c0f41 --- /dev/null +++ b/test-network-kind/README.md @@ -0,0 +1,269 @@ + +# Kubernetes Test Network + +This directory includes a set of kubernetes deployment manifests, scripts, and configuration files suitable +for running the Hyperledger Fabric test network on a local [KIND](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) +cluster. + +This is currently an experimental branch. No attempt has been made to optimize or streamline the actual +deployment to kubernetes - no helm charts, operators, kustomization overlays, etc. are involved at this +early genesis. This is merely a set of kube manifests suitable for replicating the test network on +Kubernetes. + + +## Areas for Improvement + +- [ ] Introduce `fabctl` as a bridge between objectives running locally and activities running remotely (`network.sh` equivalent, e.g. see [fabric-hyper-kube](https://github.com/hyperledgendary/fabric-hyper-kube)) +- [ ] Provide simple scripts or CLI driver routines (e.g. `network.sh up` -> `kubectl apply ...`) +- [ ] `cryptogen` -> Configure a CA +- [ ] couchdb state database +- [ ] KIND is only one path to a Kube. Check that we are also in good shape with minikube, IBM Fyre, IKS, aws, OCP, azure, etc. +- [ ] Use kustomize, ~helm~, operator, etc. etc. to properly integrate and install. +- [ ] The manifests directly pull 2.3.2 fabric images and have an imagePullPolicy: Always. Find a better technique to pull :latest tag from docker hub or the kind control plane. +- [ ] The fabric config files (2.3.2) are also hard-wired into the /config folder. It would be nice if this project could use the fab release archive (or better - directly from git), and override the stanzas in core.yaml (e.g. externalBuilder) +- [ ] Publish [fabric-ccs-builder](https://github.com/hyperledgendary/fabric-ccs-builder) image to docker hub +- [ ] Publish [asset-transfer-basic](../asset-transfer-basic/chaincode-external) and external chaincode sample images to docker hub. +- [ ] The peer deployments currently mount the chaincode application bundle into a volume at launch time. This is wrong - chaincode bundles must come AFTER the peers have been deployed, and should not force a peer pod restart. +- [ ] Pick out the CC_PACKAGE_ID from `peer chaincode install` and load into a configmap / k8s secret / env +- [ ] Configure multiple pvc - one per network node, rather than one shared volume for all network elements. +- [ ] Configure the Fabric REST sample - needs attention in configuring connection profiles, pems, CAs, and signing keys. + +## Prerequisites + +- [Docker](https://www.docker.com) +- [kubectl](https://kubernetes.io/docs/tasks/tools/) +- [KIND](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) +- [fabric-ccs-builder](#fabric-ccs-builder) docker image + +### Fabric CCS Builder + +Smart contracts running on Kubernetes rely extensively on the [Chaincode as a Service](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html) +deployment pattern. This test network uses the [fabric-ccs-builder](https://github.com/jkneubuh/fabric-ccs-builder/tree/feature/docker-bundle) +image `release`, `build`, and `detect` binaries, copied into the peer pods via an init container at +deployment time. Before starting the test network, build the ccs image locally and push to the KIND control plane: + +```shell +git clone https://github.com/hyperledgendary/fabric-ccs-builder.git /tmp/fabric-ccs-builder + +docker build -t hyperledgendary/fabric-ccs-builder /tmp/fabric-ccs-builder +``` + +## Test Network + +### Kube + +Create a Kubernetes cluster and [load docker images](https://kind.sigs.k8s.io/docs/user/quick-start/#loading-an-image-into-your-cluster) into the KIND control plane. +```shell +kind create cluster + +kind load docker-image hyperledgendary/fabric-ccs-builder +``` + +Create a dedicated namespace and persistent volume for the test-network: +```shell +kubectl create -f kube/pv-fabric.yaml +kubectl create -f kube/ns-test-network.yaml +kubectl -n test-network create -f kube/pvc-fabric.yaml +``` + +### Network Config + +```shell +kubectl -n test-network create configmap fabric-config --from-file=config/ +kubectl -n test-network create configmap chaincode-config --from-file=chaincode/ +``` + +### Channel Artifacts + +```shell +kubectl -n test-network create -f kube/debug.yaml +kubectl -n test-network create -f kube/job-crypto-config.yaml +kubectl -n test-network create -f kube/job-orderer-genesis.yaml +kubectl -n test-network create -f kube/job-create-channel-config.yaml +kubectl -n test-network create -f kube/job-update-org1-anchor-peers.yaml +kubectl -n test-network create -f kube/job-update-org2-anchor-peers.yaml +``` +(Wait for these jobs to complete. It can take a few seconds for images to be pulled from docker hub.) + +### Orderers +```shell +kubectl -n test-network apply -f kube/orderer1.yaml +kubectl -n test-network apply -f kube/orderer2.yaml +kubectl -n test-network apply -f kube/orderer3.yaml +``` + +### Peers +```shell +kubectl -n test-network apply -f kube/org1-peer1.yaml +kubectl -n test-network apply -f kube/org1-peer2.yaml +kubectl -n test-network apply -f kube/org2-peer1.yaml +kubectl -n test-network apply -f kube/org2-peer2.yaml +``` + +### Create `mychannel` + +```shell +kubectl -n test-network exec deploy/org1-peer1 -i -t -- /bin/sh + +export CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp + +peer channel \ + create \ + -c mychannel \ + -o orderer1:6050 \ + -f /var/hyperledger/fabric/channel-artifacts/mychannel.tx \ + --outputBlock /var/hyperledger/fabric/channel-artifacts/mychannel.block \ + --tls \ + --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/ca.crt + +peer channel \ + update \ + -o orderer1:6050 \ + -c mychannel \ + -f /var/hyperledger/fabric/channel-artifacts/Org1MSPanchors.tx \ + --tls \ + --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/ca.crt + +exit +``` + +### Join Peers + +```shell +kubectl \ + -n test-network \ + exec deploy/org1-peer1 \ + -i -t -- \ + /bin/sh -c 'CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp peer channel join -b /var/hyperledger/fabric/channel-artifacts/mychannel.block' +``` +```shell +kubectl \ + -n test-network \ + exec deploy/org1-peer2 \ + -i -t -- \ + /bin/sh -c 'CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp peer channel join -b /var/hyperledger/fabric/channel-artifacts/mychannel.block' +``` + +```shell +kubectl \ + -n test-network \ + exec deploy/org2-peer1 \ + -i -t -- \ + /bin/sh -c 'CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp peer channel join -b /var/hyperledger/fabric/channel-artifacts/mychannel.block' +``` + +```shell +kubectl \ + -n test-network \ + exec deploy/org2-peer2 \ + -i -t -- \ + /bin/sh -c 'CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp peer channel join -b /var/hyperledger/fabric/channel-artifacts/mychannel.block' +``` + +## Chaincode + +### Install + +```shell +kubectl -n test-network exec deploy/org1-peer1 -i -t -- /bin/sh +export CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp + +peer lifecycle \ + chaincode install \ + /var/hyperledger/fabric/chaincode/asset-transfer-basic.tgz + +exit +``` + +### Launch External Chaincode + +- [ ] Determine `CHAINCODE_ID` from install command and load as a config map / env entry in the cc deployment spec. +- [ ] Use an [insecure docker registry](bin/make-kind-with-reg.sh) to build and deploy chaincode images without Docker hub or the kind control plane. + +```shell +docker build \ + -t hyperledger/asset-transfer-basic \ + ../asset-transfer-basic/chaincode-external + +kind load docker-image hyperledger/asset-transfer-basic +``` + +```shell +kubectl -n test-network apply -f kube/cc-asset-transfer-basic.yaml +``` + +### Approve and Commit + +```shell +kubectl -n test-network exec deploy/org1-peer1 -i -t -- /bin/sh +export FABRIC_LOGGING_SPEC=INFO +export CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp +export CC_PACKAGE_ID=basic_1.0:d730a5ce916e120f2a2509ee33527a0df68cadac678f5eb196737ad10ba42da9 + +peer lifecycle \ + chaincode approveformyorg \ + -o orderer1:6050 \ + --channelID mychannel \ + --name basic \ + --version 1 \ + --package-id $CC_PACKAGE_ID \ + --sequence 1 \ + --tls \ + --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/msp/tlscacerts/tlsca.example.com-cert.pem + +peer lifecycle \ + chaincode commit \ + -o orderer1:6050 \ + --channelID mychannel \ + --name basic \ + --version 1 \ + --sequence 1 \ + --tls \ + --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/msp/tlscacerts/tlsca.example.com-cert.pem +``` + +### Query + +(run on org1-peer1) +```shell +peer chaincode \ + invoke \ + -o orderer1:6050 \ + -C mychannel \ + -n basic \ + -c '{"Args":["CreateAsset","1","blue","35","tom","1000"]}' \ + --tls \ + --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/ca.crt \ + +sleep 2 + +peer chaincode \ + query \ + -C mychannel \ + -n basic \ + -c '{"Args":["ReadAsset","1"]}' + +exit +``` + +### Reset Network + +```shell +kubectl -n test-network delete deployment --all +kubectl -n test-network delete pod --all +kubectl -n test-network delete service --all +kubectl -n test-network delete configmap --all +kubectl -n test-network delete secret --all +kubectl -n test-network create -f kube/job-scrub-fabric-volume.yaml +kubectl -n test-network wait --for=condition=complete --timeout=60s job/job-scrub-fabric-volume +kubectl -n test-network delete job --all +``` +[GOTO Config](#network-config) + +or ... +```shell +kind delete cluster +``` +[GOTO Kube](#kube) + + diff --git a/test-network-kind/bin/make-kind-with-reg.sh b/test-network-kind/bin/make-kind-with-reg.sh new file mode 100755 index 00000000..7967f049 --- /dev/null +++ b/test-network-kind/bin/make-kind-with-reg.sh @@ -0,0 +1,31 @@ +#!/bin/sh +set -o errexit + +# create registry container unless it already exists +reg_name='kind-registry' +reg_port='5000' +running="$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" +if [ "${running}" != 'true' ]; then + docker run \ + -d --restart=always -p "${reg_port}:5000" --name "${reg_name}" \ + registry:2 +fi + +# create a cluster with the local registry enabled in containerd +cat <i#U+VFK&ND7=cSe=m1f{l2UM1phQ}O; zPZZ$v5CPR(3JOXkl?ACvRtid~6(y-fd5JknIv~-U#H7?5kZ@9Bab|LSN@`MRdc2{Y zff85kK)ZSrPzxmIr=;oubAVoY70v7*l>dzlOyK$7+ytEe4Gl)~KV5))HwVMBrBaCu z%x}-1=4v(&U=6rl=Xzq7N09u&e?3dmj%3WbU=z0V|GgC#To1lmB2r{F-C(-GW$CpG zzh8QhROFWKuFzr<+Bz-8cdwdd{(Dhf$wi{QOJ`l2q~w%+D5LF!;_VuabH&o(Gt+n< zN*&u9w}$ud^!jbV7p(suQFiAjR@AX*k8W{)T%+h?->kdjTY_o$Th&9$mujkn&z){= za8SS0>yFunQ>9|>9HRsZ4GNwr)IZyAr|&sQ<>p7G+fT}M7&rzx1V_Or7zLwXXaWER KuR2fw3;+PCTEQCt literal 0 HcmV?d00001 diff --git a/test-network-kind/chaincode/asset-transfer-basic-debug/code.tar.gz b/test-network-kind/chaincode/asset-transfer-basic-debug/code.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..917183e3ea65e2c527e66b53682a91dc4ad46144 GIT binary patch literal 196 zcmV;#06YI5iwFSbr5a%X1MSbt3WG2Z1yI+1Maa5HQXirIjHG77XqwPGR;B;msL(~h z?xYlQHkUA$Fw+~Yq4(10Vsb`jM<9eWRfU#hO}!>LZ|@Z?8KM=9rJB)_B0_7zXokok z+k6Pla~oHgW)0yQ#=Tyw4a1jzwo}kM|HLCl2y-DUIEPz=N8@}UOh1Dyr1oGnSM4Rj yr==+*SDlwPFu^Z%O58T^%5@g*L0S-TFmUA{f9AhFFG-Rl+3^C~YpR5_6PvK%zN`NvSy?;iSak%;b1OJp(1K+JScO zD4;G#&QD3z1Lgp|^eUR!K`8$l8yLg#zpflK<-?Pl(r%LH*lM5q&;R8V zeZT%^dSt8Z>-jrUd!9OJcDqy_F4E+7Y*|+jCh_W`*jxqO*~t^~lQ&;V%9*?G!IRjU zgN@S;^j?YDQR7;27ut90j9b6pVr)3IKg48gT#& F006&U#9jaZ literal 0 HcmV?d00001 diff --git a/test-network-kind/chaincode/asset-transfer-basic/code.tar.gz b/test-network-kind/chaincode/asset-transfer-basic/code.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..b97295ec651b611441110513b23591fb282734e2 GIT binary patch literal 195 zcmV;!06hO6iwFQqb^u`j1MSbj3c@f924K&7in6nlRJMtGnbEZwcFqo)_9VW$?FJr1 zy$uoiK?&tgOCl#@P&z%C-9VGstN{S(vShIy>T0gAU+yzrau!aEq2`007$)T3rAD literal 0 HcmV?d00001 diff --git a/test-network-kind/chaincode/asset-transfer-basic/connection.json b/test-network-kind/chaincode/asset-transfer-basic/connection.json new file mode 100644 index 00000000..1e210c05 --- /dev/null +++ b/test-network-kind/chaincode/asset-transfer-basic/connection.json @@ -0,0 +1,5 @@ +{ + "address": "cc-asset-transfer-basic:9999", + "dial_timeout": "10s", + "tls_required": false +} \ No newline at end of file diff --git a/test-network-kind/chaincode/asset-transfer-basic/metadata.json b/test-network-kind/chaincode/asset-transfer-basic/metadata.json new file mode 100644 index 00000000..bb7056c0 --- /dev/null +++ b/test-network-kind/chaincode/asset-transfer-basic/metadata.json @@ -0,0 +1,4 @@ +{ + "type": "external", + "label": "basic_1.0" +} \ No newline at end of file diff --git a/test-network-kind/config/configtx.yaml b/test-network-kind/config/configtx.yaml new file mode 100644 index 00000000..ab11cce4 --- /dev/null +++ b/test-network-kind/config/configtx.yaml @@ -0,0 +1,389 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +--- +################################################################################ +# +# Section: Organizations +# +# - This section defines the different organizational identities which will +# be referenced later in the configuration. +# +################################################################################ +Organizations: + + # SampleOrg defines an MSP using the sampleconfig. It should never be used + # in production but may be used as a template for other definitions + - &OrdererOrg + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: OrdererOrg + + # ID to load the MSP definition as + ID: OrdererMSP + + # MSPDir is the filesystem path which contains the MSP configuration + MSPDir: crypto-config/ordererOrganizations/example.com/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('OrdererMSP.member')" + Writers: + Type: Signature + Rule: "OR('OrdererMSP.member')" + Admins: + Type: Signature + Rule: "OR('OrdererMSP.admin')" + + OrdererEndpoints: + - orderer1:6050 + - orderer2:6050 + - orderer3:6050 + + - &Org1 + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: Org1MSP + + # ID to load the MSP definition as + ID: Org1MSP + + MSPDir: crypto-config/peerOrganizations/org1.example.com/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')" + Writers: + Type: Signature + Rule: "OR('Org1MSP.admin', 'Org1MSP.client')" + Admins: + Type: Signature + Rule: "OR('Org1MSP.admin')" + Endorsement: + Type: Signature + Rule: "OR('Org1MSP.peer')" + + # leave this flag set to true. + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: org1-peer1 + Port: 7051 + + - &Org2 + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: Org2MSP + + # ID to load the MSP definition as + ID: Org2MSP + + MSPDir: crypto-config/peerOrganizations/org2.example.com/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')" + Writers: + Type: Signature + Rule: "OR('Org2MSP.admin', 'Org2MSP.client')" + Admins: + Type: Signature + Rule: "OR('Org2MSP.admin')" + Endorsement: + Type: Signature + Rule: "OR('Org2MSP.peer')" + + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: org2-peer1 + Port: 7051 + +################################################################################ +# +# SECTION: Capabilities +# +# - This section defines the capabilities of fabric network. This is a new +# concept as of v1.1.0 and should not be utilized in mixed networks with +# v1.0.x peers and orderers. Capabilities define features which must be +# present in a fabric binary for that binary to safely participate in the +# fabric network. For instance, if a new MSP type is added, newer binaries +# might recognize and validate the signatures from this type, while older +# binaries without this support would be unable to validate those +# transactions. This could lead to different versions of the fabric binaries +# having different world states. Instead, defining a capability for a channel +# informs those binaries without this capability that they must cease +# processing transactions until they have been upgraded. For v1.0.x if any +# capabilities are defined (including a map with all capabilities turned off) +# then the v1.0.x peer will deliberately crash. +# +################################################################################ +Capabilities: + # Channel capabilities apply to both the orderers and the peers and must be + # supported by both. + # Set the value of the capability to true to require it. + Channel: &ChannelCapabilities + # V2_0 capability ensures that orderers and peers behave according + # to v2.0 channel capabilities. Orderers and peers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 capability. + # Prior to enabling V2.0 channel capabilities, ensure that all + # orderers and peers on a channel are at v2.0.0 or later. + V2_0: true + + # Orderer capabilities apply only to the orderers, and may be safely + # used with prior release peers. + # Set the value of the capability to true to require it. + Orderer: &OrdererCapabilities + # V2_0 orderer capability ensures that orderers behave according + # to v2.0 orderer capabilities. Orderers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 orderer capability. + # Prior to enabling V2.0 orderer capabilities, ensure that all + # orderers on channel are at v2.0.0 or later. + V2_0: true + + # Application capabilities apply only to the peer network, and may be safely + # used with prior release orderers. + # Set the value of the capability to true to require it. + Application: &ApplicationCapabilities + # V2_0 application capability ensures that peers behave according + # to v2.0 application capabilities. Peers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 application capability. + # Prior to enabling V2.0 application capabilities, ensure that all + # peers on channel are at v2.0.0 or later. + V2_0: true + +################################################################################ +# +# SECTION: Application +# +# - This section defines the values to encode into a config transaction or +# genesis block for application related parameters +# +################################################################################ +Application: &ApplicationDefaults + + # Organizations is the list of orgs which are defined as participants on + # the application side of the network + Organizations: + + # Policies defines the set of policies at this level of the config tree + # For Application policies, their canonical path is + # /Channel/Application/ + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + LifecycleEndorsement: + Type: Signature + Rule: "OR('Org1MSP.peer','Org2MSP.peer')" + Endorsement: + Type: Signature + Rule: "OR('Org1MSP.peer','Org2MSP.peer')" + + Capabilities: + <<: *ApplicationCapabilities +################################################################################ +# +# SECTION: Orderer +# +# - This section defines the values to encode into a config transaction or +# genesis block for orderer related parameters +# +################################################################################ +Orderer: &OrdererDefaults + + # Orderer Type: The orderer implementation to start + OrdererType: etcdraft + + EtcdRaft: + Consenters: + - Host: orderer1 + Port: 6050 + ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt + ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt + - Host: orderer2 + Port: 6050 + ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt + ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt + - Host: orderer3 + Port: 6050 + ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/server.crt + ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/server.crt + + # Options to be specified for all the etcd/raft nodes. The values here + # are the defaults for all new channels and can be modified on a + # per-channel basis via configuration updates. + Options: + # TickInterval is the time interval between two Node.Tick invocations. + #TickInterval: 500ms default + TickInterval: 2500ms + + # ElectionTick is the number of Node.Tick invocations that must pass + # between elections. That is, if a follower does not receive any + # message from the leader of current term before ElectionTick has + # elapsed, it will become candidate and start an election. + # ElectionTick must be greater than HeartbeatTick. + # ElectionTick: 10 default + ElectionTick: 5 + + # HeartbeatTick is the number of Node.Tick invocations that must + # pass between heartbeats. That is, a leader sends heartbeat + # messages to maintain its leadership every HeartbeatTick ticks. + HeartbeatTick: 1 + + # MaxInflightBlocks limits the max number of in-flight append messages + # during optimistic replication phase. + MaxInflightBlocks: 5 + + # SnapshotIntervalSize defines number of bytes per which a snapshot is taken + SnapshotIntervalSize: 16 MB + + # Batch Timeout: The amount of time to wait before creating a batch + BatchTimeout: 2s + + # Batch Size: Controls the number of messages batched into a block + BatchSize: + + # Max Message Count: The maximum number of messages to permit in a batch + MaxMessageCount: 10 + + # Absolute Max Bytes: The absolute maximum number of bytes allowed for + # the serialized messages in a batch. + AbsoluteMaxBytes: 99 MB + + # Preferred Max Bytes: The preferred maximum number of bytes allowed for + # the serialized messages in a batch. A message larger than the preferred + # max bytes will result in a batch larger than preferred max bytes. + PreferredMaxBytes: 512 KB + + # Organizations is the list of orgs which are defined as participants on + # the orderer side of the network + Organizations: + + # Policies defines the set of policies at this level of the config tree + # For Orderer policies, their canonical path is + # /Channel/Orderer/ + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + # BlockValidation specifies what signatures must be included in the block + # from the orderer for the peer to validate it. + BlockValidation: + Type: ImplicitMeta + Rule: "ANY Writers" + +################################################################################ +# +# CHANNEL +# +# This section defines the values to encode into a config transaction or +# genesis block for channel related parameters. +# +################################################################################ +Channel: &ChannelDefaults + # Policies defines the set of policies at this level of the config tree + # For Channel policies, their canonical path is + # /Channel/ + Policies: + # Who may invoke the 'Deliver' API + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + # Who may invoke the 'Broadcast' API + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + # By default, who may modify elements at this config level + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + + # Capabilities describes the channel level capabilities, see the + # dedicated Capabilities section elsewhere in this file for a full + # description + Capabilities: + <<: *ChannelCapabilities + +################################################################################ +# +# Profile +# +# - Different configuration profiles may be encoded here to be specified +# as parameters to the configtxgen tool +# +################################################################################ +Profiles: + + TwoOrgsOrdererGenesis: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + Organizations: + - *OrdererOrg + Capabilities: + <<: *OrdererCapabilities + Consortiums: + SampleConsortium: + Organizations: + - *Org1 + - *Org2 + TwoOrgsChannel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + - *Org2 + Capabilities: + <<: *ApplicationCapabilities + Org1Channel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + Capabilities: + <<: *ApplicationCapabilities + Org2Channel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org2 + Capabilities: + <<: *ApplicationCapabilities diff --git a/test-network-kind/config/core.yaml b/test-network-kind/config/core.yaml new file mode 100644 index 00000000..0b4738d7 --- /dev/null +++ b/test-network-kind/config/core.yaml @@ -0,0 +1,759 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################### +# +# Peer section +# +############################################################################### +peer: + + # The peer id provides a name for this peer instance and is used when + # naming docker resources. + id: jdoe + + # The networkId allows for logical separation of networks and is used when + # naming docker resources. + networkId: dev + + # The Address at local network interface this Peer will listen on. + # By default, it will listen on all network interfaces + listenAddress: 0.0.0.0:7051 + + # The endpoint this peer uses to listen for inbound chaincode connections. + # If this is commented-out, the listen address is selected to be + # the peer's address (see below) with port 7052 + # chaincodeListenAddress: 0.0.0.0:7052 + + # The endpoint the chaincode for this peer uses to connect to the peer. + # If this is not specified, the chaincodeListenAddress address is selected. + # And if chaincodeListenAddress is not specified, address is selected from + # peer address (see below). If specified peer address is invalid then it + # will fallback to the auto detected IP (local IP) regardless of the peer + # addressAutoDetect value. + # chaincodeAddress: 0.0.0.0:7052 + + # When used as peer config, this represents the endpoint to other peers + # in the same organization. For peers in other organization, see + # gossip.externalEndpoint for more info. + # When used as CLI config, this means the peer's endpoint to interact with + address: 0.0.0.0:7051 + + # Whether the Peer should programmatically determine its address + # This case is useful for docker containers. + # When set to true, will override peer address. + addressAutoDetect: false + + # Keepalive settings for peer server and clients + keepalive: + # Interval is the duration after which if the server does not see + # any activity from the client it pings the client to see if it's alive + interval: 7200s + # Timeout is the duration the server waits for a response + # from the client after sending a ping before closing the connection + timeout: 20s + # MinInterval is the minimum permitted time between client pings. + # If clients send pings more frequently, the peer server will + # disconnect them + minInterval: 60s + # Client keepalive settings for communicating with other peer nodes + client: + # Interval is the time between pings to peer nodes. This must + # greater than or equal to the minInterval specified by peer + # nodes + interval: 60s + # Timeout is the duration the client waits for a response from + # peer nodes before closing the connection + timeout: 20s + # DeliveryClient keepalive settings for communication with ordering + # nodes. + deliveryClient: + # Interval is the time between pings to ordering nodes. This must + # greater than or equal to the minInterval specified by ordering + # nodes. + interval: 60s + # Timeout is the duration the client waits for a response from + # ordering nodes before closing the connection + timeout: 20s + + + # Gossip related configuration + gossip: + # Bootstrap set to initialize gossip with. + # This is a list of other peers that this peer reaches out to at startup. + # Important: The endpoints here have to be endpoints of peers in the same + # organization, because the peer would refuse connecting to these endpoints + # unless they are in the same organization as the peer. + bootstrap: 127.0.0.1:7051 + + # NOTE: orgLeader and useLeaderElection parameters are mutual exclusive. + # Setting both to true would result in the termination of the peer + # since this is undefined state. If the peers are configured with + # useLeaderElection=false, make sure there is at least 1 peer in the + # organization that its orgLeader is set to true. + + # Defines whenever peer will initialize dynamic algorithm for + # "leader" selection, where leader is the peer to establish + # connection with ordering service and use delivery protocol + # to pull ledger blocks from ordering service. + useLeaderElection: false + # Statically defines peer to be an organization "leader", + # where this means that current peer will maintain connection + # with ordering service and disseminate block across peers in + # its own organization. Multiple peers or all peers in an organization + # may be configured as org leaders, so that they all pull + # blocks directly from ordering service. + orgLeader: true + + # Interval for membershipTracker polling + membershipTrackerInterval: 5s + + # Overrides the endpoint that the peer publishes to peers + # in its organization. For peers in foreign organizations + # see 'externalEndpoint' + endpoint: + # Maximum count of blocks stored in memory + maxBlockCountToStore: 10 + # Max time between consecutive message pushes(unit: millisecond) + maxPropagationBurstLatency: 10ms + # Max number of messages stored until a push is triggered to remote peers + maxPropagationBurstSize: 10 + # Number of times a message is pushed to remote peers + propagateIterations: 1 + # Number of peers selected to push messages to + propagatePeerNum: 3 + # Determines frequency of pull phases(unit: second) + # Must be greater than digestWaitTime + responseWaitTime + pullInterval: 4s + # Number of peers to pull from + pullPeerNum: 3 + # Determines frequency of pulling state info messages from peers(unit: second) + requestStateInfoInterval: 4s + # Determines frequency of pushing state info messages to peers(unit: second) + publishStateInfoInterval: 4s + # Maximum time a stateInfo message is kept until expired + stateInfoRetentionInterval: + # Time from startup certificates are included in Alive messages(unit: second) + publishCertPeriod: 10s + # Should we skip verifying block messages or not (currently not in use) + skipBlockVerification: false + # Dial timeout(unit: second) + dialTimeout: 3s + # Connection timeout(unit: second) + connTimeout: 2s + # Buffer size of received messages + recvBuffSize: 20 + # Buffer size of sending messages + sendBuffSize: 200 + # Time to wait before pull engine processes incoming digests (unit: second) + # Should be slightly smaller than requestWaitTime + digestWaitTime: 1s + # Time to wait before pull engine removes incoming nonce (unit: milliseconds) + # Should be slightly bigger than digestWaitTime + requestWaitTime: 1500ms + # Time to wait before pull engine ends pull (unit: second) + responseWaitTime: 2s + # Alive check interval(unit: second) + aliveTimeInterval: 5s + # Alive expiration timeout(unit: second) + aliveExpirationTimeout: 25s + # Reconnect interval(unit: second) + reconnectInterval: 25s + # Max number of attempts to connect to a peer + maxConnectionAttempts: 120 + # Message expiration factor for alive messages + msgExpirationFactor: 20 + # This is an endpoint that is published to peers outside of the organization. + # If this isn't set, the peer will not be known to other organizations. + externalEndpoint: + # Leader election service configuration + election: + # Longest time peer waits for stable membership during leader election startup (unit: second) + startupGracePeriod: 15s + # Interval gossip membership samples to check its stability (unit: second) + membershipSampleInterval: 1s + # Time passes since last declaration message before peer decides to perform leader election (unit: second) + leaderAliveThreshold: 10s + # Time between peer sends propose message and declares itself as a leader (sends declaration message) (unit: second) + leaderElectionDuration: 5s + + pvtData: + # pullRetryThreshold determines the maximum duration of time private data corresponding for a given block + # would be attempted to be pulled from peers until the block would be committed without the private data + pullRetryThreshold: 60s + # As private data enters the transient store, it is associated with the peer's ledger's height at that time. + # transientstoreMaxBlockRetention defines the maximum difference between the current ledger's height upon commit, + # and the private data residing inside the transient store that is guaranteed not to be purged. + # Private data is purged from the transient store when blocks with sequences that are multiples + # of transientstoreMaxBlockRetention are committed. + transientstoreMaxBlockRetention: 1000 + # pushAckTimeout is the maximum time to wait for an acknowledgement from each peer + # at private data push at endorsement time. + pushAckTimeout: 3s + # Block to live pulling margin, used as a buffer + # to prevent peer from trying to pull private data + # from peers that is soon to be purged in next N blocks. + # This helps a newly joined peer catch up to current + # blockchain height quicker. + btlPullMargin: 10 + # the process of reconciliation is done in an endless loop, while in each iteration reconciler tries to + # pull from the other peers the most recent missing blocks with a maximum batch size limitation. + # reconcileBatchSize determines the maximum batch size of missing private data that will be reconciled in a + # single iteration. + reconcileBatchSize: 10 + # reconcileSleepInterval determines the time reconciler sleeps from end of an iteration until the beginning + # of the next reconciliation iteration. + reconcileSleepInterval: 1m + # reconciliationEnabled is a flag that indicates whether private data reconciliation is enable or not. + reconciliationEnabled: true + # skipPullingInvalidTransactionsDuringCommit is a flag that indicates whether pulling of invalid + # transaction's private data from other peers need to be skipped during the commit time and pulled + # only through reconciler. + skipPullingInvalidTransactionsDuringCommit: false + # implicitCollectionDisseminationPolicy specifies the dissemination policy for the peer's own implicit collection. + # When a peer endorses a proposal that writes to its own implicit collection, below values override the default values + # for disseminating private data. + # Note that it is applicable to all channels the peer has joined. The implication is that requiredPeerCount has to + # be smaller than the number of peers in a channel that has the lowest numbers of peers from the organization. + implicitCollectionDisseminationPolicy: + # requiredPeerCount defines the minimum number of eligible peers to which the peer must successfully + # disseminate private data for its own implicit collection during endorsement. Default value is 0. + requiredPeerCount: 0 + # maxPeerCount defines the maximum number of eligible peers to which the peer will attempt to + # disseminate private data for its own implicit collection during endorsement. Default value is 1. + maxPeerCount: 1 + + # Gossip state transfer related configuration + state: + # indicates whenever state transfer is enabled or not + # default value is true, i.e. state transfer is active + # and takes care to sync up missing blocks allowing + # lagging peer to catch up to speed with rest network. + # Keep in mind that when peer.gossip.useLeaderElection is true + # and there are several peers in the organization, + # or peer.gossip.useLeaderElection is false alongside with + # peer.gossip.orgleader being false, the peer's ledger may lag behind + # the rest of the peers and will never catch up due to state transfer + # being disabled. + enabled: false + # checkInterval interval to check whether peer is lagging behind enough to + # request blocks via state transfer from another peer. + checkInterval: 10s + # responseTimeout amount of time to wait for state transfer response from + # other peers + responseTimeout: 3s + # batchSize the number of blocks to request via state transfer from another peer + batchSize: 10 + # blockBufferSize reflects the size of the re-ordering buffer + # which captures blocks and takes care to deliver them in order + # down to the ledger layer. The actual buffer size is bounded between + # 0 and 2*blockBufferSize, each channel maintains its own buffer + blockBufferSize: 20 + # maxRetries maximum number of re-tries to ask + # for single state transfer request + maxRetries: 3 + + # TLS Settings + tls: + # Require server-side TLS + enabled: false + # Require client certificates / mutual TLS for inbound connections. + # Note that clients that are not configured to use a certificate will + # fail to connect to the peer. + clientAuthRequired: false + # X.509 certificate used for TLS server + cert: + file: tls/server.crt + # Private key used for TLS server + key: + file: tls/server.key + # rootcert.file represents the trusted root certificate chain used for verifying certificates + # of other nodes during outbound connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + rootcert: + file: tls/ca.crt + # If mutual TLS is enabled, clientRootCAs.files contains a list of additional root certificates + # used for verifying certificates of client connections. + # It augments the set of TLS CA certificates available from the MSPs of each channel’s configuration. + # Minimally, set your organization's TLS CA root certificate so that the peer can receive join channel requests. + clientRootCAs: + files: + - tls/ca.crt + # Private key used for TLS when making client connections. + # If not set, peer.tls.key.file will be used instead + clientKey: + file: + # X.509 certificate used for TLS when making client connections. + # If not set, peer.tls.cert.file will be used instead + clientCert: + file: + + # Authentication contains configuration parameters related to authenticating + # client messages + authentication: + # the acceptable difference between the current server time and the + # client's time as specified in a client request message + timewindow: 15m + + # Path on the file system where peer will store data (eg ledger). This + # location must be access control protected to prevent unintended + # modification that might corrupt the peer operations. + fileSystemPath: /var/hyperledger/production + + # BCCSP (Blockchain crypto provider): Select which crypto implementation or + # library to use + BCCSP: + Default: SW + # Settings for the SW crypto provider (i.e. when DEFAULT: SW) + SW: + # TODO: The default Hash and Security level needs refactoring to be + # fully configurable. Changing these defaults requires coordination + # SHA2 is hardcoded in several places, not only BCCSP + Hash: SHA2 + Security: 256 + # Location of Key Store + FileKeyStore: + # If "", defaults to 'mspConfigPath'/keystore + KeyStore: + # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) + PKCS11: + # Location of the PKCS11 module library + Library: + # Token Label + Label: + # User PIN + Pin: + Hash: + Security: + + # Path on the file system where peer will find MSP local configurations + mspConfigPath: msp + + # Identifier of the local MSP + # ----!!!!IMPORTANT!!!-!!!IMPORTANT!!!-!!!IMPORTANT!!!!---- + # Deployers need to change the value of the localMspId string. + # In particular, the name of the local MSP ID of a peer needs + # to match the name of one of the MSPs in each of the channel + # that this peer is a member of. Otherwise this peer's messages + # will not be identified as valid by other nodes. + localMspId: SampleOrg + + # CLI common client config options + client: + # connection timeout + connTimeout: 3s + + # Delivery service related config + deliveryclient: + # It sets the total time the delivery service may spend in reconnection + # attempts until its retry logic gives up and returns an error + reconnectTotalTimeThreshold: 3600s + + # It sets the delivery service <-> ordering service node connection timeout + connTimeout: 3s + + # It sets the delivery service maximal delay between consecutive retries + reConnectBackoffThreshold: 3600s + + # A list of orderer endpoint addresses which should be overridden + # when found in channel configurations. + addressOverrides: + # - from: + # to: + # caCertsFile: + # - from: + # to: + # caCertsFile: + + # Type for the local MSP - by default it's of type bccsp + localMspType: bccsp + + # Used with Go profiling tools only in none production environment. In + # production, it should be disabled (eg enabled: false) + profile: + enabled: false + listenAddress: 0.0.0.0:6060 + + # Handlers defines custom handlers that can filter and mutate + # objects passing within the peer, such as: + # Auth filter - reject or forward proposals from clients + # Decorators - append or mutate the chaincode input passed to the chaincode + # Endorsers - Custom signing over proposal response payload and its mutation + # Valid handler definition contains: + # - A name which is a factory method name defined in + # core/handlers/library/library.go for statically compiled handlers + # - library path to shared object binary for pluggable filters + # Auth filters and decorators are chained and executed in the order that + # they are defined. For example: + # authFilters: + # - + # name: FilterOne + # library: /opt/lib/filter.so + # - + # name: FilterTwo + # decorators: + # - + # name: DecoratorOne + # - + # name: DecoratorTwo + # library: /opt/lib/decorator.so + # Endorsers are configured as a map that its keys are the endorsement system chaincodes that are being overridden. + # Below is an example that overrides the default ESCC and uses an endorsement plugin that has the same functionality + # as the default ESCC. + # If the 'library' property is missing, the name is used as the constructor method in the builtin library similar + # to auth filters and decorators. + # endorsers: + # escc: + # name: DefaultESCC + # library: /etc/hyperledger/fabric/plugin/escc.so + handlers: + authFilters: + - + name: DefaultAuth + - + name: ExpirationCheck # This filter checks identity x509 certificate expiration + decorators: + - + name: DefaultDecorator + endorsers: + escc: + name: DefaultEndorsement + library: + validators: + vscc: + name: DefaultValidation + library: + + # library: /etc/hyperledger/fabric/plugin/escc.so + # Number of goroutines that will execute transaction validation in parallel. + # By default, the peer chooses the number of CPUs on the machine. Set this + # variable to override that choice. + # NOTE: overriding this value might negatively influence the performance of + # the peer so please change this value only if you know what you're doing + validatorPoolSize: + + # The discovery service is used by clients to query information about peers, + # such as - which peers have joined a certain channel, what is the latest + # channel config, and most importantly - given a chaincode and a channel, + # what possible sets of peers satisfy the endorsement policy. + discovery: + enabled: true + # Whether the authentication cache is enabled or not. + authCacheEnabled: true + # The maximum size of the cache, after which a purge takes place + authCacheMaxSize: 1000 + # The proportion (0 to 1) of entries that remain in the cache after the cache is purged due to overpopulation + authCachePurgeRetentionRatio: 0.75 + # Whether to allow non-admins to perform non channel scoped queries. + # When this is false, it means that only peer admins can perform non channel scoped queries. + orgMembersAllowedAccess: false + + # Limits is used to configure some internal resource limits. + limits: + # Concurrency limits the number of concurrently running requests to a service on each peer. + # Currently this option is only applied to endorser service and deliver service. + # When the property is missing or the value is 0, the concurrency limit is disabled for the service. + concurrency: + # endorserService limits concurrent requests to endorser service that handles chaincode deployment, query and invocation, + # including both user chaincodes and system chaincodes. + endorserService: 2500 + # deliverService limits concurrent event listeners registered to deliver service for blocks and transaction events. + deliverService: 2500 + +############################################################################### +# +# VM section +# +############################################################################### +vm: + + # Endpoint of the vm management system. For docker can be one of the following in general + # unix:///var/run/docker.sock + # http://localhost:2375 + # https://localhost:2376 + endpoint: unix:///var/run/docker.sock + + # settings for docker vms + docker: + tls: + enabled: false + ca: + file: docker/ca.crt + cert: + file: docker/tls.crt + key: + file: docker/tls.key + + # Enables/disables the standard out/err from chaincode containers for + # debugging purposes + attachStdout: false + + # Parameters on creating docker container. + # Container may be efficiently created using ipam & dns-server for cluster + # NetworkMode - sets the networking mode for the container. Supported + # standard values are: `host`(default),`bridge`,`ipvlan`,`none`. + # Dns - a list of DNS servers for the container to use. + # Note: `Privileged` `Binds` `Links` and `PortBindings` properties of + # Docker Host Config are not supported and will not be used if set. + # LogConfig - sets the logging driver (Type) and related options + # (Config) for Docker. For more info, + # https://docs.docker.com/engine/admin/logging/overview/ + # Note: Set LogConfig using Environment Variables is not supported. + hostConfig: + NetworkMode: host + Dns: + # - 192.168.0.1 + LogConfig: + Type: json-file + Config: + max-size: "50m" + max-file: "5" + Memory: 2147483648 + +############################################################################### +# +# Chaincode section +# +############################################################################### +chaincode: + + # The id is used by the Chaincode stub to register the executing Chaincode + # ID with the Peer and is generally supplied through ENV variables + # the `path` form of ID is provided when installing the chaincode. + # The `name` is used for all other requests and can be any string. + id: + path: + name: + + # Generic builder environment, suitable for most chaincode types + builder: $(DOCKER_NS)/fabric-ccenv:$(TWO_DIGIT_VERSION) + + # Enables/disables force pulling of the base docker images (listed below) + # during user chaincode instantiation. + # Useful when using moving image tags (such as :latest) + pull: false + + golang: + # golang will never need more than baseos + runtime: $(DOCKER_NS)/fabric-baseos:$(TWO_DIGIT_VERSION) + + # whether or not golang chaincode should be linked dynamically + dynamicLink: false + + java: + # This is an image based on java:openjdk-8 with addition compiler + # tools added for java shim layer packaging. + # This image is packed with shim layer libraries that are necessary + # for Java chaincode runtime. + runtime: $(DOCKER_NS)/fabric-javaenv:$(TWO_DIGIT_VERSION) + + node: + # This is an image based on node:$(NODE_VER)-alpine + runtime: $(DOCKER_NS)/fabric-nodeenv:$(TWO_DIGIT_VERSION) + + # 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: + - path: /var/hyperledger/fabric/chaincode/ccs-builder + name: ccs-builder + propagateEnvironment: + - HOME + - CORE_PEER_ID + - CORE_PEER_LOCALMSPID + + # The maximum duration to wait for the chaincode build and install process + # to complete. + installTimeout: 300s + + # Timeout duration for starting up a container and waiting for Register + # to come through. + startuptimeout: 300s + + # Timeout duration for Invoke and Init calls to prevent runaway. + # This timeout is used by all chaincodes in all the channels, including + # system chaincodes. + # Note that during Invoke, if the image is not available (e.g. being + # cleaned up when in development environment), the peer will automatically + # build the image, which might take more time. In production environment, + # the chaincode image is unlikely to be deleted, so the timeout could be + # reduced accordingly. + executetimeout: 30s + + # There are 2 modes: "dev" and "net". + # In dev mode, user runs the chaincode after starting peer from + # command line on local machine. + # In net mode, peer will run chaincode in a docker container. + mode: net + + # keepalive in seconds. In situations where the communication goes through a + # proxy that does not support keep-alive, this parameter will maintain connection + # between peer and chaincode. + # A value <= 0 turns keepalive off + keepalive: 0 + + # enabled system chaincodes + system: + _lifecycle: enable + cscc: enable + lscc: enable + qscc: enable + + # Logging section for the chaincode container + logging: + # Default level for all loggers within the chaincode container + level: info + # Override default level for the 'shim' logger + shim: warning + # Format for the chaincode container logs + format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}' + +############################################################################### +# +# Ledger section - ledger configuration encompasses both the blockchain +# and the state +# +############################################################################### +ledger: + + blockchain: + + state: + # stateDatabase - options are "goleveldb", "CouchDB" + # goleveldb - default state database stored in goleveldb. + # CouchDB - store state database in CouchDB + stateDatabase: goleveldb + # Limit on the number of records to return per query + totalQueryLimit: 100000 + couchDBConfig: + # It is recommended to run CouchDB on the same server as the peer, and + # not map the CouchDB container port to a server port in docker-compose. + # Otherwise proper security must be provided on the connection between + # CouchDB client (on the peer) and server. + couchDBAddress: 127.0.0.1:5984 + # This username must have read and write authority on CouchDB + username: + # The password is recommended to pass as an environment variable + # during start up (eg CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD). + # If it is stored here, the file must be access control protected + # to prevent unintended users from discovering the password. + password: + # Number of retries for CouchDB errors + maxRetries: 3 + # Number of retries for CouchDB errors during peer startup. + # The delay between retries doubles for each attempt. + # Default of 10 retries results in 11 attempts over 2 minutes. + maxRetriesOnStartup: 10 + # CouchDB request timeout (unit: duration, e.g. 20s) + requestTimeout: 35s + # Limit on the number of records per each CouchDB query + # Note that chaincode queries are only bound by totalQueryLimit. + # Internally the chaincode may execute multiple CouchDB queries, + # each of size internalQueryLimit. + internalQueryLimit: 1000 + # Limit on the number of records per CouchDB bulk update batch + maxBatchUpdateSize: 1000 + # Warm indexes after every N blocks. + # This option warms any indexes that have been + # deployed to CouchDB after every N blocks. + # A value of 1 will warm indexes after every block commit, + # to ensure fast selector queries. + # Increasing the value may improve write efficiency of peer and CouchDB, + # but may degrade query response time. + warmIndexesAfterNBlocks: 1 + # Create the _global_changes system database + # This is optional. Creating the global changes database will require + # additional system resources to track changes and maintain the database + createGlobalChangesDB: false + # CacheSize denotes the maximum mega bytes (MB) to be allocated for the in-memory state + # cache. Note that CacheSize needs to be a multiple of 32 MB. If it is not a multiple + # of 32 MB, the peer would round the size to the next multiple of 32 MB. + # To disable the cache, 0 MB needs to be assigned to the cacheSize. + cacheSize: 64 + + history: + # enableHistoryDatabase - options are true or false + # Indicates if the history of key updates should be stored. + # All history 'index' will be stored in goleveldb, regardless if using + # CouchDB or alternate database for the state. + enableHistoryDatabase: true + + pvtdataStore: + # the maximum db batch size for converting + # the ineligible missing data entries to eligible missing data entries + collElgProcMaxDbBatchSize: 5000 + # the minimum duration (in milliseconds) between writing + # two consecutive db batches for converting the ineligible missing data entries to eligible missing data entries + collElgProcDbBatchesInterval: 1000 + # The missing data entries are classified into two categories: + # (1) prioritized + # (2) deprioritized + # Initially, all missing data are in the prioritized list. When the + # reconciler is unable to fetch the missing data from other peers, + # the unreconciled missing data would be moved to the deprioritized list. + # The reconciler would retry deprioritized missing data after every + # deprioritizedDataReconcilerInterval (unit: minutes). Note that the + # interval needs to be greater than the reconcileSleepInterval + deprioritizedDataReconcilerInterval: 60m + + snapshots: + # Path on the file system where peer will store ledger snapshots + rootDir: /var/hyperledger/production/snapshots + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9443 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # most operations service endpoints require client authentication when TLS + # is enabled. clientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # metrics provider is one of statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd metrics + prefix: diff --git a/test-network-kind/config/crypto-config.yaml b/test-network-kind/config/crypto-config.yaml new file mode 100644 index 00000000..c7f5178e --- /dev/null +++ b/test-network-kind/config/crypto-config.yaml @@ -0,0 +1,59 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# --------------------------------------------------------------------------- +# "OrdererOrgs" - Definition of organizations managing orderer nodes +# --------------------------------------------------------------------------- +OrdererOrgs: + - Name: Orderer + Domain: example.com + EnableNodeOUs: true + + Specs: + - Hostname: orderer1 + SANS: + - 0.0.0.0 + - Hostname: orderer2 + SANS: + - 0.0.0.0 + - Hostname: orderer3 + SANS: + - 0.0.0.0 + - Hostname: orderer4 + SANS: + - 0.0.0.0 + - Hostname: orderer5 + SANS: + - 0.0.0.0 + +# --------------------------------------------------------------------------- +# "PeerOrgs" - Definition of organizations managing peer nodes +# --------------------------------------------------------------------------- +PeerOrgs: + - Name: Org1 + Domain: org1.example.com + EnableNodeOUs: true + Specs: + - Hostname: org1-peer1 + SANS: + - 0.0.0.0 + - Hostname: org1-peer2 + SANS: + - 0.0.0.0 + Users: + Count: 1 + + - Name: Org2 + Domain: org2.example.com + EnableNodeOUs: true + Specs: + - Hostname: org2-peer1 + SANS: + - 0.0.0.0 + - Hostname: org2-peer2 + SANS: + - 0.0.0.0 + Users: + Count: 1 diff --git a/test-network-kind/config/orderer.yaml b/test-network-kind/config/orderer.yaml new file mode 100644 index 00000000..fc545546 --- /dev/null +++ b/test-network-kind/config/orderer.yaml @@ -0,0 +1,420 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + + +--- +################################################################################ +# +# Orderer Configuration +# +# - This controls the type and configuration of the orderer. +# +################################################################################ +General: + # Listen address: The IP on which to bind to listen. + ListenAddress: 127.0.0.1 + + # Listen port: The port on which to bind to listen. + ListenPort: 7050 + + # TLS: TLS settings for the GRPC server. + TLS: + # Require server-side TLS + Enabled: false + # PrivateKey governs the file location of the private key of the TLS certificate. + PrivateKey: tls/server.key + # Certificate governs the file location of the server TLS certificate. + Certificate: tls/server.crt + # RootCAs contains a list of additional root certificates used for verifying certificates + # of other orderer nodes during outbound connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + RootCAs: + - tls/ca.crt + # Require client certificates / mutual TLS for inbound connections. + ClientAuthRequired: false + # If mutual TLS is enabled, ClientRootCAs contains a list of additional root certificates + # used for verifying certificates of client connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + ClientRootCAs: + # Keepalive settings for the GRPC server. + Keepalive: + # ServerMinInterval is the minimum permitted time between client pings. + # If clients send pings more frequently, the server will + # disconnect them. + ServerMinInterval: 60s + # ServerInterval is the time between pings to clients. + ServerInterval: 7200s + # ServerTimeout is the duration the server waits for a response from + # a client before closing the connection. + ServerTimeout: 20s + # Cluster settings for ordering service nodes that communicate with other ordering service nodes + # such as Raft based ordering service. + Cluster: + # SendBufferSize is the maximum number of messages in the egress buffer. + # Consensus messages are dropped if the buffer is full, and transaction + # messages are waiting for space to be freed. + SendBufferSize: 10 + + # ClientCertificate governs the file location of the client TLS certificate + # used to establish mutual TLS connections with other ordering service nodes. + # If not set, the server General.TLS.Certificate is re-used. + ClientCertificate: + # ClientPrivateKey governs the file location of the private key of the client TLS certificate. + # If not set, the server General.TLS.PrivateKey is re-used. + ClientPrivateKey: + + # The below 4 properties should be either set together, or be unset together. + # If they are set, then the orderer node uses a separate listener for intra-cluster + # communication. If they are unset, then the general orderer listener is used. + # This is useful if you want to use a different TLS server certificates on the + # client-facing and the intra-cluster listeners. + + # ListenPort defines the port on which the cluster listens to connections. + ListenPort: + # ListenAddress defines the IP on which to listen to intra-cluster communication. + ListenAddress: + # ServerCertificate defines the file location of the server TLS certificate used for intra-cluster + # communication. + ServerCertificate: + # ServerPrivateKey defines the file location of the private key of the TLS certificate. + ServerPrivateKey: + + # Bootstrap method: The method by which to obtain the bootstrap block + # system channel is specified. The option can be one of: + # "file" - path to a file containing the genesis block or config block of system channel + # "none" - allows an orderer to start without a system channel configuration + BootstrapMethod: file + + # Bootstrap file: The file containing the bootstrap block to use when + # initializing the orderer system channel and BootstrapMethod is set to + # "file". The bootstrap file can be the genesis block, and it can also be + # a config block for late bootstrap of some consensus methods like Raft. + # Generate a genesis block by updating $FABRIC_CFG_PATH/configtx.yaml and + # using configtxgen command with "-outputBlock" option. + # Defaults to file "genesisblock" (in $FABRIC_CFG_PATH directory) if not specified. + BootstrapFile: + + # LocalMSPDir is where to find the private crypto material needed by the + # orderer. It is set relative here as a default for dev environments but + # should be changed to the real location in production. + LocalMSPDir: msp + + # LocalMSPID is the identity to register the local MSP material with the MSP + # manager. IMPORTANT: The local MSP ID of an orderer needs to match the MSP + # ID of one of the organizations defined in the orderer system channel's + # /Channel/Orderer configuration. The sample organization defined in the + # sample configuration provided has an MSP ID of "SampleOrg". + LocalMSPID: SampleOrg + + # Enable an HTTP service for Go "pprof" profiling as documented at: + # https://golang.org/pkg/net/http/pprof + Profile: + Enabled: false + Address: 0.0.0.0:6060 + + # BCCSP configures the blockchain crypto service providers. + BCCSP: + # Default specifies the preferred blockchain crypto service provider + # to use. If the preferred provider is not available, the software + # based provider ("SW") will be used. + # Valid providers are: + # - SW: a software based crypto provider + # - PKCS11: a CA hardware security module crypto provider. + Default: SW + + # SW configures the software based blockchain crypto provider. + SW: + # TODO: The default Hash and Security level needs refactoring to be + # fully configurable. Changing these defaults requires coordination + # SHA2 is hardcoded in several places, not only BCCSP + Hash: SHA2 + Security: 256 + # Location of key store. If this is unset, a location will be + # chosen using: 'LocalMSPDir'/keystore + FileKeyStore: + KeyStore: + + # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) + PKCS11: + # Location of the PKCS11 module library + Library: + # Token Label + Label: + # User PIN + Pin: + Hash: + Security: + FileKeyStore: + KeyStore: + + # Authentication contains configuration parameters related to authenticating + # client messages + Authentication: + # the acceptable difference between the current server time and the + # client's time as specified in a client request message + TimeWindow: 15m + + +################################################################################ +# +# SECTION: File Ledger +# +# - This section applies to the configuration of the file ledger. +# +################################################################################ +FileLedger: + + # Location: The directory to store the blocks in. + Location: /var/hyperledger/production/orderer + +################################################################################ +# +# SECTION: Kafka +# +# - This section applies to the configuration of the Kafka-based orderer, and +# its interaction with the Kafka cluster. +# +################################################################################ +Kafka: + + # Retry: What do if a connection to the Kafka cluster cannot be established, + # or if a metadata request to the Kafka cluster needs to be repeated. + Retry: + # When a new channel is created, or when an existing channel is reloaded + # (in case of a just-restarted orderer), the orderer interacts with the + # Kafka cluster in the following ways: + # 1. It creates a Kafka producer (writer) for the Kafka partition that + # corresponds to the channel. + # 2. It uses that producer to post a no-op CONNECT message to that + # partition + # 3. It creates a Kafka consumer (reader) for that partition. + # If any of these steps fail, they will be re-attempted every + # for a total of , and then every + # for a total of until they succeed. + # Note that the orderer will be unable to write to or read from a + # channel until all of the steps above have been completed successfully. + ShortInterval: 5s + ShortTotal: 10m + LongInterval: 5m + LongTotal: 12h + # Affects the socket timeouts when waiting for an initial connection, a + # response, or a transmission. See Config.Net for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + NetworkTimeouts: + DialTimeout: 10s + ReadTimeout: 10s + WriteTimeout: 10s + # Affects the metadata requests when the Kafka cluster is in the middle + # of a leader election.See Config.Metadata for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Metadata: + RetryBackoff: 250ms + RetryMax: 3 + # What to do if posting a message to the Kafka cluster fails. See + # Config.Producer for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Producer: + RetryBackoff: 100ms + RetryMax: 3 + # What to do if reading from the Kafka cluster fails. See + # Config.Consumer for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Consumer: + RetryBackoff: 2s + # Settings to use when creating Kafka topics. Only applies when + # Kafka.Version is v0.10.1.0 or higher + Topic: + # The number of Kafka brokers across which to replicate the topic + ReplicationFactor: 3 + # Verbose: Enable logging for interactions with the Kafka cluster. + Verbose: false + + # TLS: TLS settings for the orderer's connection to the Kafka cluster. + TLS: + + # Enabled: Use TLS when connecting to the Kafka cluster. + Enabled: false + + # PrivateKey: PEM-encoded private key the orderer will use for + # authentication. + PrivateKey: + # As an alternative to specifying the PrivateKey here, uncomment the + # following "File" key and specify the file name from which to load the + # value of PrivateKey. + #File: path/to/PrivateKey + + # Certificate: PEM-encoded signed public key certificate the orderer will + # use for authentication. + Certificate: + # As an alternative to specifying the Certificate here, uncomment the + # following "File" key and specify the file name from which to load the + # value of Certificate. + #File: path/to/Certificate + + # RootCAs: PEM-encoded trusted root certificates used to validate + # certificates from the Kafka cluster. + RootCAs: + # As an alternative to specifying the RootCAs here, uncomment the + # following "File" key and specify the file name from which to load the + # value of RootCAs. + #File: path/to/RootCAs + + # SASLPlain: Settings for using SASL/PLAIN authentication with Kafka brokers + SASLPlain: + # Enabled: Use SASL/PLAIN to authenticate with Kafka brokers + Enabled: false + # User: Required when Enabled is set to true + User: + # Password: Required when Enabled is set to true + Password: + + # Kafka protocol version used to communicate with the Kafka cluster brokers + # (defaults to 0.10.2.0 if not specified) + Version: + +################################################################################ +# +# Debug Configuration +# +# - This controls the debugging options for the orderer +# +################################################################################ +Debug: + + # BroadcastTraceDir when set will cause each request to the Broadcast service + # for this orderer to be written to a file in this directory + BroadcastTraceDir: + + # DeliverTraceDir when set will cause each request to the Deliver service + # for this orderer to be written to a file in this directory + DeliverTraceDir: + +################################################################################ +# +# Operations Configuration +# +# - This configures the operations server endpoint for the orderer +# +################################################################################ +Operations: + # host and port for the operations server + ListenAddress: 127.0.0.1:8443 + + # TLS configuration for the operations endpoint + TLS: + # TLS enabled + Enabled: false + + # Certificate is the location of the PEM encoded TLS certificate + Certificate: + + # PrivateKey points to the location of the PEM-encoded key + PrivateKey: + + # Most operations service endpoints require client authentication when TLS + # is enabled. ClientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + ClientAuthRequired: false + + # Paths to PEM encoded ca certificates to trust for client authentication + ClientRootCAs: [] + +################################################################################ +# +# Metrics Configuration +# +# - This configures metrics collection for the orderer +# +################################################################################ +Metrics: + # The metrics provider is one of statsd, prometheus, or disabled + Provider: disabled + + # The statsd configuration + Statsd: + # network type: tcp or udp + Network: udp + + # the statsd server address + Address: 127.0.0.1:8125 + + # The interval at which locally cached counters and gauges are pushed + # to statsd; timings are pushed immediately + WriteInterval: 30s + + # The prefix is prepended to all emitted statsd metrics + Prefix: + +################################################################################ +# +# Admin Configuration +# +# - This configures the admin server endpoint for the orderer +# +################################################################################ +Admin: + # host and port for the admin server + ListenAddress: 127.0.0.1:9443 + + # TLS configuration for the admin endpoint + TLS: + # TLS enabled + Enabled: false + + # Certificate is the location of the PEM encoded TLS certificate + Certificate: + + # PrivateKey points to the location of the PEM-encoded key + PrivateKey: + + # Most admin service endpoints require client authentication when TLS + # is enabled. ClientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + # + # NOTE: When TLS is enabled, the admin endpoint requires mutual TLS. The + # orderer will panic on startup if this value is set to false. + ClientAuthRequired: true + + # Paths to PEM encoded ca certificates to trust for client authentication + ClientRootCAs: [] + +################################################################################ +# +# Channel participation API Configuration +# +# - This provides the channel participation API configuration for the orderer. +# - Channel participation uses the ListenAddress and TLS settings of the Admin +# service. +# +################################################################################ +ChannelParticipation: + # Channel participation API is enabled. + Enabled: false + + # The maximum size of the request body when joining a channel. + MaxRequestBodySize: 1 MB + + +################################################################################ +# +# Consensus Configuration +# +# - This section contains config options for a consensus plugin. It is opaque +# to orderer, and completely up to consensus implementation to make use of. +# +################################################################################ +Consensus: + # The allowed key-value pairs here depend on consensus plugin. For etcd/raft, + # we use following options: + + # WALDir specifies the location at which Write Ahead Logs for etcd/raft are + # stored. Each channel will have its own subdir named after channel ID. + WALDir: /var/hyperledger/production/orderer/etcdraft/wal + + # SnapDir specifies the location at which snapshots for etcd/raft are + # stored. Each channel will have its own subdir named after channel ID. + SnapDir: /var/hyperledger/production/orderer/etcdraft/snapshot diff --git a/test-network-kind/kube/cc-asset-transfer-basic.yaml b/test-network-kind/kube/cc-asset-transfer-basic.yaml new file mode 100644 index 00000000..8760949b --- /dev/null +++ b/test-network-kind/kube/cc-asset-transfer-basic.yaml @@ -0,0 +1,46 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cc-asset-transfer-basic +spec: + replicas: 1 + selector: + matchLabels: + app: cc-asset-transfer-basic + template: + metadata: + labels: + app: cc-asset-transfer-basic + spec: + containers: + - name: main + image: hyperledger/asset-transfer-basic + imagePullPolicy: IfNotPresent + env: + - name: CHAINCODE_SERVER_ADDRESS + value: 0.0.0.0:9999 + + # todo: load with an envFrom and a dynamic config map with the ID. + - name: CHAINCODE_ID + value: basic_1.0:d730a5ce916e120f2a2509ee33527a0df68cadac678f5eb196737ad10ba42da9 + ports: + - containerPort: 9999 + +--- +apiVersion: v1 +kind: Service +metadata: + name: cc-asset-transfer-basic +spec: + ports: + - name: chaincode + port: 9999 + protocol: TCP + selector: + app: cc-asset-transfer-basic \ No newline at end of file diff --git a/test-network-kind/kube/debug.yaml b/test-network-kind/kube/debug.yaml new file mode 100644 index 00000000..2adbae51 --- /dev/null +++ b/test-network-kind/kube/debug.yaml @@ -0,0 +1,55 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + run: debug + name: debug + namespace: test-network +spec: + progressDeadlineSeconds: 600 + replicas: 1 + selector: + matchLabels: + run: debug + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + run: debug + spec: + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 + containers: + - image: radial/busyboxplus:curl + imagePullPolicy: Always + name: main + resources: {} + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: fabric-config + configMap: + name: fabric-config diff --git a/test-network-kind/kube/job-create-channel-config.yaml b/test-network-kind/kube/job-create-channel-config.yaml new file mode 100644 index 00000000..bd445527 --- /dev/null +++ b/test-network-kind/kube/job-create-channel-config.yaml @@ -0,0 +1,45 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: batch/v1 +kind: Job +metadata: + generateName: create-channel-config- +spec: + backoffLimit: 1 + template: + metadata: + name: create-channel-config + spec: + restartPolicy: "Never" + containers: + - name: main + image: hyperledger/fabric-tools:2.3.2 + # todo: latest tag is not at docker hub + imagePullPolicy: Always + env: + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric + command: [ + "configtxgen", + "-channelID", "mychannel", + "-profile", "TwoOrgsChannel", + "-outputCreateChannelTx", "/var/hyperledger/fabric/channel-artifacts/mychannel.tx", + ] + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: config-volume + mountPath: /var/hyperledger/fabric/configtx.yaml + subPath: configtx.yaml + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: config-volume + configMap: + name: fabric-config + diff --git a/test-network-kind/kube/job-crypto-config.yaml b/test-network-kind/kube/job-crypto-config.yaml new file mode 100644 index 00000000..7a9d6278 --- /dev/null +++ b/test-network-kind/kube/job-crypto-config.yaml @@ -0,0 +1,41 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: batch/v1 +kind: Job +metadata: + generateName: crypto-config- +spec: + backoffLimit: 1 + template: + metadata: + name: crypto-config + spec: + restartPolicy: "Never" + containers: + - name: main + image: hyperledger/fabric-tools:2.3.2 + # todo: fixme for KIND clusters + imagePullPolicy: Always + command: + - cryptogen + - generate + - --config=/var/hyperledger/fabric/crypto-config.yaml + - --output=/var/hyperledger/fabric/crypto-config + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: config-volume + mountPath: /var/hyperledger/fabric/crypto-config.yaml + subPath: crypto-config.yaml + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: config-volume + configMap: + name: fabric-config + diff --git a/test-network-kind/kube/job-orderer-genesis.yaml b/test-network-kind/kube/job-orderer-genesis.yaml new file mode 100644 index 00000000..089f699e --- /dev/null +++ b/test-network-kind/kube/job-orderer-genesis.yaml @@ -0,0 +1,44 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: batch/v1 +kind: Job +metadata: + generateName: orderer-genesis- +spec: + backoffLimit: 1 + template: + metadata: + name: orderer-genesis + spec: + restartPolicy: "Never" + containers: + - name: main + image: hyperledger/fabric-tools:2.3.2 + # todo: latest tag is not at docker hub + imagePullPolicy: Always + env: + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric + command: [ + "configtxgen", + "-profile", "TwoOrgsOrdererGenesis", + "-channelID", "test-system-channel-name", + "-outputBlock", "/var/hyperledger/fabric/channel-artifacts/genesis.block" + ] + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: config-volume + mountPath: /var/hyperledger/fabric/configtx.yaml + subPath: configtx.yaml + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: config-volume + configMap: + name: fabric-config \ No newline at end of file diff --git a/test-network-kind/kube/job-scrub-fabric-volume.yaml b/test-network-kind/kube/job-scrub-fabric-volume.yaml new file mode 100644 index 00000000..1ad56bd0 --- /dev/null +++ b/test-network-kind/kube/job-scrub-fabric-volume.yaml @@ -0,0 +1,32 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: job-scrub-fabric-volume +spec: + backoffLimit: 0 + completions: 1 + template: + metadata: + name: scrub-fabric-volume + spec: + restartPolicy: "Never" + containers: + - name: main + image: alpine + command: + - sh + - -c + - "rm -rvf /var/hyperledger/fabric/*" + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric \ No newline at end of file diff --git a/test-network-kind/kube/job-update-org1-anchor-peers.yaml b/test-network-kind/kube/job-update-org1-anchor-peers.yaml new file mode 100644 index 00000000..cc87a402 --- /dev/null +++ b/test-network-kind/kube/job-update-org1-anchor-peers.yaml @@ -0,0 +1,45 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: batch/v1 +kind: Job +metadata: + generateName: update-org1-anchor-peers- +spec: + backoffLimit: 1 + template: + metadata: + name: update-org1-anchor-peers + spec: + restartPolicy: "Never" + containers: + - name: main + image: hyperledger/fabric-tools:2.3.2 + # todo: latest tag is not at docker hub + imagePullPolicy: Always + env: + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric + command: [ + "configtxgen", + "-profile", "TwoOrgsChannel", + "-outputAnchorPeersUpdate", "/var/hyperledger/fabric/channel-artifacts/Org1MSPanchors.tx", + "-channelID", "mychannel", + "-asOrg", "Org1MSP", + ] + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: config-volume + mountPath: /var/hyperledger/fabric/configtx.yaml + subPath: configtx.yaml + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: config-volume + configMap: + name: fabric-config \ No newline at end of file diff --git a/test-network-kind/kube/job-update-org2-anchor-peers.yaml b/test-network-kind/kube/job-update-org2-anchor-peers.yaml new file mode 100644 index 00000000..af32bc28 --- /dev/null +++ b/test-network-kind/kube/job-update-org2-anchor-peers.yaml @@ -0,0 +1,45 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: batch/v1 +kind: Job +metadata: + generateName: update-org2-anchor-peers- +spec: + backoffLimit: 1 + template: + metadata: + name: update-org2-anchor-peers + spec: + restartPolicy: "Never" + containers: + - name: main + image: hyperledger/fabric-tools:2.3.2 + # todo: latest tag is not at docker hub + imagePullPolicy: Always + env: + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric + command: [ + "configtxgen", + "-profile", "TwoOrgsChannel", + "-outputAnchorPeersUpdate", "/var/hyperledger/fabric/channel-artifacts/Org2MSPanchors.tx", + "-channelID", "mychannel", + "-asOrg", "Org2MSP", + ] + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: config-volume + mountPath: /var/hyperledger/fabric/configtx.yaml + subPath: configtx.yaml + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: config-volume + configMap: + name: fabric-config diff --git a/test-network-kind/kube/ns-test-network.yaml b/test-network-kind/kube/ns-test-network.yaml new file mode 100644 index 00000000..f9ef39e0 --- /dev/null +++ b/test-network-kind/kube/ns-test-network.yaml @@ -0,0 +1,10 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: Namespace +metadata: + name: test-network diff --git a/test-network-kind/kube/orderer1.yaml b/test-network-kind/kube/orderer1.yaml new file mode 100644 index 00000000..2b1503e1 --- /dev/null +++ b/test-network-kind/kube/orderer1.yaml @@ -0,0 +1,87 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: orderer1-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info" + ORDERER_GENERAL_LISTENADDRESS: "0.0.0.0" + ORDERER_GENERAL_LISTENPORT: "6050" + ORDERER_GENERAL_LOCALMSPID: OrdererMSP + ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/msp + ORDERER_GENERAL_TLS_ENABLED: "true" + ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.key + ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt + # following setting is not really needed at runtime since channel config has ca root certs, but we need to override the default in orderer.yaml + ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/ca.crt + ORDERER_GENERAL_BOOTSTRAPMETHOD: file + ORDERER_GENERAL_BOOTSTRAPFILE: /var/hyperledger/fabric/channel-artifacts/genesis.block + ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer + ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer/etcdraft/wal + ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer/etcdraft/wal + ORDERER_OPERATIONS_LISTENADDRESS: "0.0.0.0:8443" + ORDERER_ADMIN_LISTENADDRESS: "0.0.0.0:9443" + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: orderer1 +spec: + replicas: 1 + selector: + matchLabels: + app: orderer1 + template: + metadata: + labels: + app: orderer1 + spec: + containers: + - name: main + image: hyperledger/fabric-orderer:2.3.2 + imagePullPolicy: Always + envFrom: + - configMapRef: + name: orderer1-config + ports: + - containerPort: 6050 + - containerPort: 8443 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: fabric-config + configMap: + name: fabric-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: orderer1 +spec: + ports: + - name: general + port: 6050 + protocol: TCP + - name: operations + port: 8443 + protocol: TCP + - name: admin + port: 9443 + protocol: TCP + selector: + app: orderer1 \ No newline at end of file diff --git a/test-network-kind/kube/orderer2.yaml b/test-network-kind/kube/orderer2.yaml new file mode 100644 index 00000000..cc2636b5 --- /dev/null +++ b/test-network-kind/kube/orderer2.yaml @@ -0,0 +1,87 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: orderer2-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info" + ORDERER_GENERAL_LISTENADDRESS: "0.0.0.0" + ORDERER_GENERAL_LISTENPORT: "6050" + ORDERER_GENERAL_LOCALMSPID: OrdererMSP + ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/msp + ORDERER_GENERAL_TLS_ENABLED: "true" + ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.key + ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt + # following setting is not really needed at runtime since channel config has ca root certs, but we need to override the default in orderer.yaml + ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/ca.crt + ORDERER_GENERAL_BOOTSTRAPMETHOD: file + ORDERER_GENERAL_BOOTSTRAPFILE: /var/hyperledger/fabric/channel-artifacts/genesis.block + ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer2 + ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer2/etcdraft/wal + ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer2/etcdraft/wal + ORDERER_OPERATIONS_LISTENADDRESS: "0.0.0.0:8443" + ORDERER_ADMIN_LISTENADDRESS: "0.0.0.0:9443" + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: orderer2 +spec: + replicas: 1 + selector: + matchLabels: + app: orderer2 + template: + metadata: + labels: + app: orderer2 + spec: + containers: + - name: main + image: hyperledger/fabric-orderer:2.3.2 + imagePullPolicy: Always + envFrom: + - configMapRef: + name: orderer2-config + ports: + - containerPort: 6050 + - containerPort: 8443 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: fabric-config + configMap: + name: fabric-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: orderer2 +spec: + ports: + - name: general + port: 6050 + protocol: TCP + - name: operations + port: 8443 + protocol: TCP + - name: admin + port: 9443 + protocol: TCP + selector: + app: orderer2 \ No newline at end of file diff --git a/test-network-kind/kube/orderer3.yaml b/test-network-kind/kube/orderer3.yaml new file mode 100644 index 00000000..0d53fc6d --- /dev/null +++ b/test-network-kind/kube/orderer3.yaml @@ -0,0 +1,87 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: orderer3-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info" + ORDERER_GENERAL_LISTENADDRESS: "0.0.0.0" + ORDERER_GENERAL_LISTENPORT: "6050" + ORDERER_GENERAL_LOCALMSPID: OrdererMSP + ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/msp + ORDERER_GENERAL_TLS_ENABLED: "true" + ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/server.key + ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/server.crt + # following setting is not really needed at runtime since channel config has ca root certs, but we need to override the default in orderer.yaml + ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/ca.crt + ORDERER_GENERAL_BOOTSTRAPMETHOD: file + ORDERER_GENERAL_BOOTSTRAPFILE: /var/hyperledger/fabric/channel-artifacts/genesis.block + ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer3 + ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer3/etcdraft/wal + ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer3/etcdraft/wal + ORDERER_OPERATIONS_LISTENADDRESS: "0.0.0.0:8443" + ORDERER_ADMIN_LISTENADDRESS: "0.0.0.0:9443" + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: orderer3 +spec: + replicas: 1 + selector: + matchLabels: + app: orderer3 + template: + metadata: + labels: + app: orderer3 + spec: + containers: + - name: main + image: hyperledger/fabric-orderer:2.3.2 + imagePullPolicy: Always + envFrom: + - configMapRef: + name: orderer3-config + ports: + - containerPort: 6050 + - containerPort: 8443 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: fabric-config + configMap: + name: fabric-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: orderer3 +spec: + ports: + - name: general + port: 6050 + protocol: TCP + - name: operations + port: 8443 + protocol: TCP + - name: admin + port: 9443 + protocol: TCP + selector: + app: orderer3 \ No newline at end of file diff --git a/test-network-kind/kube/org1-peer1.yaml b/test-network-kind/kube/org1-peer1.yaml new file mode 100644 index 00000000..78c09db5 --- /dev/null +++ b/test-network-kind/kube/org1-peer1.yaml @@ -0,0 +1,110 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org1-peer1-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" + CORE_PEER_TLS_ENABLED: "true" + CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/server.crt + CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/server.key + CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/ca.crt + CORE_PEER_ID: org1-peer1.org1.example.com + CORE_PEER_ADDRESS: org1-peer1:7051 + CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 + CORE_PEER_CHAINCODEADDRESS: org1-peer1:7052 + CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 + # bootstrap peer is the other peer in the same org + CORE_PEER_GOSSIP_BOOTSTRAP: org1-peer2:7051 + CORE_PEER_GOSSIP_EXTERNALENDPOINT: org1-peer1:7051 + CORE_PEER_LOCALMSPID: Org1MSP + CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/msp + CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 + CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org1-peer1.org1.example.com + CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org1-peer1.org1.example.com/snapshots + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org1-peer1 +spec: + replicas: 1 + selector: + matchLabels: + app: org1-peer1 + template: + metadata: + labels: + app: org1-peer1 + spec: + containers: + - name: main + image: hyperledger/fabric-peer:2.3.2 + imagePullPolicy: Always + envFrom: + - configMapRef: + name: org1-peer1-config + ports: + - containerPort: 7051 + - containerPort: 7052 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + - name: ccs-builder + mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin + - name: chaincode-config + mountPath: /var/hyperledger/fabric/chaincode/ + + # load the external chaincode builder into the peer image prior to peer launch. + initContainers: + - name: fabric-ccs-builder + # todo: publish this image to docker hub. It's currently read from the kind docker context. + image: hyperledgendary/fabric-ccs-builder + imagePullPolicy: IfNotPresent + command: [sh, -c] + args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] + volumeMounts: + - name: ccs-builder + mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: fabric-config + configMap: + name: fabric-config + - name: ccs-builder + emptyDir: {} + - name: chaincode-config + configMap: + name: chaincode-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org1-peer1 +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + - name: chaincode + port: 7052 + protocol: TCP + - name: operations + port: 9443 + protocol: TCP + selector: + app: org1-peer1 \ No newline at end of file diff --git a/test-network-kind/kube/org1-peer2.yaml b/test-network-kind/kube/org1-peer2.yaml new file mode 100644 index 00000000..d43a7405 --- /dev/null +++ b/test-network-kind/kube/org1-peer2.yaml @@ -0,0 +1,105 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org1-peer2-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" + CORE_PEER_TLS_ENABLED: "true" + CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/server.crt + CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/server.key + CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/ca.crt + CORE_PEER_ID: org1-peer2.org1.example.com + CORE_PEER_ADDRESS: org1-peer2:7051 + CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 + CORE_PEER_CHAINCODEADDRESS: org1-peer2:7052 + CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 + # bootstrap peer is the other peer in the same org + CORE_PEER_GOSSIP_BOOTSTRAP: org1-peer1:7051 + CORE_PEER_GOSSIP_EXTERNALENDPOINT: org1-peer2:7051 + CORE_PEER_LOCALMSPID: Org1MSP + CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/msp + CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 + CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org1-peer2.org1.example.com + CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org1-peer2.org1.example.com/snapshots + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org1-peer2 +spec: + replicas: 1 + selector: + matchLabels: + app: org1-peer2 + template: + metadata: + labels: + app: org1-peer2 + spec: + containers: + - name: main + image: hyperledger/fabric-peer:2.3.2 + imagePullPolicy: Always + envFrom: + - configMapRef: + name: org1-peer2-config + ports: + - containerPort: 7051 + - containerPort: 7052 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + - name: ccs-builder + mountPath: /var/hyperledger/fabric/external-chaincode/builder + + # load the external chaincode binaries into the peer image prior to peer launch. + initContainers: + - name: fabric-ccs-builder + # todo: publish this image to docker hub. It's currently read from the kind docker context. + image: hyperledgendary/fabric-ccs-builder + imagePullPolicy: IfNotPresent + command: [sh, -c] + args: ["cp /go/bin/* /podshare"] + volumeMounts: + - name: ccs-builder + mountPath: /podshare + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: fabric-config + configMap: + name: fabric-config + - name: ccs-builder + emptyDir: {} + +--- +apiVersion: v1 +kind: Service +metadata: + name: org1-peer2 +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + - name: chaincode + port: 7052 + protocol: TCP + - name: operations + port: 9443 + protocol: TCP + selector: + app: org1-peer2 \ No newline at end of file diff --git a/test-network-kind/kube/org2-peer1.yaml b/test-network-kind/kube/org2-peer1.yaml new file mode 100644 index 00000000..7cfe6850 --- /dev/null +++ b/test-network-kind/kube/org2-peer1.yaml @@ -0,0 +1,105 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org2-peer1-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" + CORE_PEER_TLS_ENABLED: "true" + CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/server.crt + CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/server.key + CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/ca.crt + CORE_PEER_ID: org2-peer1.org2.example.com + CORE_PEER_ADDRESS: org2-peer1:7051 + CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 + CORE_PEER_CHAINCODEADDRESS: org2-peer1:7052 + CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 + # bootstrap peer is the other peer in the same org + CORE_PEER_GOSSIP_BOOTSTRAP: org2-peer2:7051 + CORE_PEER_GOSSIP_EXTERNALENDPOINT: org2-peer1:7051 + CORE_PEER_LOCALMSPID: Org2MSP + CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/msp + CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 + CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org2-peer1.org2.example.com + CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org2-peer1.org2.example.com/snapshots + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org2-peer1 +spec: + replicas: 1 + selector: + matchLabels: + app: org2-peer1 + template: + metadata: + labels: + app: org2-peer1 + spec: + containers: + - name: main + image: hyperledger/fabric-peer:2.3.2 + imagePullPolicy: Always + envFrom: + - configMapRef: + name: org2-peer1-config + ports: + - containerPort: 7051 + - containerPort: 7052 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + - name: ccs-builder + mountPath: /var/hyperledger/fabric/external-chaincode/builder + + # load the external chaincode binaries into the peer image prior to peer launch. + initContainers: + - name: fabric-ccs-builder + # todo: publish this image to docker hub. It's currently read from the kind docker context. + image: hyperledgendary/fabric-ccs-builder + imagePullPolicy: IfNotPresent + command: [sh, -c] + args: ["cp /go/bin/* /podshare"] + volumeMounts: + - name: ccs-builder + mountPath: /podshare + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: fabric-config + configMap: + name: fabric-config + - name: ccs-builder + emptyDir: {} + +--- +apiVersion: v1 +kind: Service +metadata: + name: org2-peer1 +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + - name: chaincode + port: 7052 + protocol: TCP + - name: operations + port: 9443 + protocol: TCP + selector: + app: org2-peer1 \ No newline at end of file diff --git a/test-network-kind/kube/org2-peer2.yaml b/test-network-kind/kube/org2-peer2.yaml new file mode 100644 index 00000000..570e2312 --- /dev/null +++ b/test-network-kind/kube/org2-peer2.yaml @@ -0,0 +1,105 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org2-peer2-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" + CORE_PEER_TLS_ENABLED: "true" + CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/server.crt + CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/server.key + CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/ca.crt + CORE_PEER_ID: org2-peer2.org2.example.com + CORE_PEER_ADDRESS: org2-peer2:7051 + CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 + CORE_PEER_CHAINCODEADDRESS: org2-peer2:7052 + CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 + # bootstrap peer is the other peer in the same org + CORE_PEER_GOSSIP_BOOTSTRAP: org2-peer1:7051 + CORE_PEER_GOSSIP_EXTERNALENDPOINT: org2-peer2:7051 + CORE_PEER_LOCALMSPID: Org2MSP + CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/msp + CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 + CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org2-peer2.org2.example.com + CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org2-peer2.org2.example.com/snapshots + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org2-peer2 +spec: + replicas: 1 + selector: + matchLabels: + app: org2-peer2 + template: + metadata: + labels: + app: org2-peer2 + spec: + containers: + - name: main + image: hyperledger/fabric-peer:2.3.2 + imagePullPolicy: Always + envFrom: + - configMapRef: + name: org2-peer2-config + ports: + - containerPort: 7051 + - containerPort: 7052 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger/fabric + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + - name: ccs-builder + mountPath: /var/hyperledger/fabric/external-chaincode/builder + + # load the external chaincode binaries into the peer image prior to peer launch. + initContainers: + - name: fabric-ccs-builder + # todo: publish this image to docker hub. It's currently read from the kind docker context. + image: hyperledgendary/fabric-ccs-builder + imagePullPolicy: IfNotPresent + command: [sh, -c] + args: ["cp /go/bin/* /podshare"] + volumeMounts: + - name: ccs-builder + mountPath: /podshare + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric + - name: fabric-config + configMap: + name: fabric-config + - name: ccs-builder + emptyDir: {} + +--- +apiVersion: v1 +kind: Service +metadata: + name: org2-peer2 +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + - name: chaincode + port: 7052 + protocol: TCP + - name: operations + port: 9443 + protocol: TCP + selector: + app: org2-peer2 \ No newline at end of file diff --git a/test-network-kind/kube/pv-fabric.yaml b/test-network-kind/kube/pv-fabric.yaml new file mode 100644 index 00000000..b77aae53 --- /dev/null +++ b/test-network-kind/kube/pv-fabric.yaml @@ -0,0 +1,18 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: fabric +spec: + storageClassName: standard + accessModes: + - ReadWriteOnce + capacity: + storage: 2Gi + hostPath: + path: /var/hyperledger/fabric diff --git a/test-network-kind/kube/pvc-fabric.yaml b/test-network-kind/kube/pvc-fabric.yaml new file mode 100644 index 00000000..861ae55b --- /dev/null +++ b/test-network-kind/kube/pvc-fabric.yaml @@ -0,0 +1,17 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: fabric +spec: + volumeName: fabric + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi From 7a727eb69a83116c3b2d886f773db2001a4364e0 Mon Sep 17 00:00:00 2001 From: Indranil Majumder Date: Thu, 16 Sep 2021 15:26:28 +0530 Subject: [PATCH 005/106] changes to support couchdb 3.1.1 Signed-off-by: Indranil Majumder --- off_chain_data/.gitignore | 5 +++++ off_chain_data/README.md | 6 +++--- off_chain_data/blockProcessing.js | 9 +++++---- off_chain_data/config.json | 2 +- off_chain_data/couchdbutil.js | 4 ++-- off_chain_data/startFabric.sh | 14 +++++++++++++- 6 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 off_chain_data/.gitignore diff --git a/off_chain_data/.gitignore b/off_chain_data/.gitignore new file mode 100644 index 00000000..cc6066a0 --- /dev/null +++ b/off_chain_data/.gitignore @@ -0,0 +1,5 @@ +addAssets.json +mychannel__lifecycle.log +mychannel_basic.log +nextblock.txt +wallet/ \ No newline at end of file diff --git a/off_chain_data/README.md b/off_chain_data/README.md index fbe4ecb4..79cde6da 100644 --- a/off_chain_data/README.md +++ b/off_chain_data/README.md @@ -38,7 +38,7 @@ The configuration for the listener is stored in the `config.json` file: "channelid": "mychannel", "use_couchdb":true, "create_history_log":true, - "couchdb_address": "http://localhost:5990" + "couchdb_address": "http://admin:password@localhost:5990" } ``` @@ -48,7 +48,7 @@ The configuration for the listener is stored in the `config.json` file: CouchDB. If set to false, only a local log of events will be stored. `create_history_log:` If true, a local log file will be created with all of the block changes. -`couchdb_address:` is the local address for an off chain CouchDB database. +`couchdb_address:` is the local address for an off chain CouchDB database with username and password. ### Create an instance of CouchDB @@ -56,7 +56,7 @@ If you set the "use_couchdb" option to true in `config.json`, you can run the following command start a local instance of CouchDB using docker: ``` -docker run --publish 5990:5984 --detach --name offchaindb couchdb:2.3.1 +docker run -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password --publish 5990:5984 --detach --name offchaindb couchdb:3.1.1 docker start offchaindb ``` diff --git a/off_chain_data/blockProcessing.js b/off_chain_data/blockProcessing.js index eed61b24..a2acb286 100644 --- a/off_chain_data/blockProcessing.js +++ b/off_chain_data/blockProcessing.js @@ -86,7 +86,7 @@ exports.processBlockEvent = async function (channelname, block, use_couchdb, nan for (var record in rwSet) { // ignore lscc events - if (rwSet[record].namespace != 'lscc') { + if (rwSet[record].namespace != '_lifecycle') { // create object to store properties const writeObject = new Object(); writeObject.blocknumber = blockNumber; @@ -108,7 +108,7 @@ exports.processBlockEvent = async function (channelname, block, use_couchdb, nan try { await writeValuesToCouchDBP(nano, channelname, writeObject); } catch (error) { - + } } } @@ -136,14 +136,14 @@ async function writeValuesToCouchDBP(nano, channelname, writeObject) { const historydbname = channelname + '_' + writeObject.chaincodeid + '_history'; // set values to the array of values received const values = writeObject.values; - + try { for (var sequence in values) { let keyvalue = values[ sequence ]; - + if ( keyvalue.is_delete == true @@ -159,6 +159,7 @@ async function writeValuesToCouchDBP(nano, channelname, writeObject) { keyvalue.value ) ) { + // insert or update value by key - this emulates world state behavior await couchdbutil.writeToCouchDB( nano, diff --git a/off_chain_data/config.json b/off_chain_data/config.json index 4df92335..5852531f 100644 --- a/off_chain_data/config.json +++ b/off_chain_data/config.json @@ -3,5 +3,5 @@ "channelid": "mychannel", "use_couchdb":true, "create_history_log":true, - "couchdb_address": "http://localhost:5990" + "couchdb_address": "http://admin:password@localhost:5990" } diff --git a/off_chain_data/couchdbutil.js b/off_chain_data/couchdbutil.js index 5e6a5329..c82c8b01 100644 --- a/off_chain_data/couchdbutil.js +++ b/off_chain_data/couchdbutil.js @@ -37,7 +37,7 @@ exports.writeToCouchDB = async function (nano, dbname, key, value) { try { await this.createDatabaseIfNotExists(nano, dbname); } catch (error) { - + console.log("Error creating the database-"+error) } const db = nano.use(dbname); @@ -82,7 +82,7 @@ exports.deleteRecord = async function (nano, dbname, key) { try { await this.createDatabaseIfNotExists(nano, dbname); } catch (error) { - + console.log("Error creating the database-"+error) } const db = nano.use(dbname); diff --git a/off_chain_data/startFabric.sh b/off_chain_data/startFabric.sh index e340bed5..b22eefc8 100755 --- a/off_chain_data/startFabric.sh +++ b/off_chain_data/startFabric.sh @@ -11,7 +11,19 @@ starttime=$(date +%s) # launch network; create channel and join peer to channel pushd ../test-network -./network.sh down + +# Fixes the issue of when running busybox in network down command on windows git bash +case "$(uname -s)" in + CYGWIN*|MINGW32*|MSYS*|MINGW*) + echo 'Running on MS Windows' + export MSYS_NO_PATHCONV=1 + ./network.sh down + unset MSYS_NO_PATHCONV + ;; + *) + ./network.sh down + ;; +esac ./network.sh up createChannel -ca -s couchdb ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go/ -ccl go From c1615b31eef94cf4e24557530c3b36ac81d41741 Mon Sep 17 00:00:00 2001 From: Indranil Majumder Date: Fri, 24 Sep 2021 10:01:18 +0530 Subject: [PATCH 006/106] Checking both the old and new lifecycle name Signed-off-by: Indranil Majumder --- off_chain_data/blockProcessing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/off_chain_data/blockProcessing.js b/off_chain_data/blockProcessing.js index a2acb286..83275abc 100644 --- a/off_chain_data/blockProcessing.js +++ b/off_chain_data/blockProcessing.js @@ -86,7 +86,7 @@ exports.processBlockEvent = async function (channelname, block, use_couchdb, nan for (var record in rwSet) { // ignore lscc events - if (rwSet[record].namespace != '_lifecycle') { + if (rwSet[record].namespace != 'lscc' && rwSet[record].namespace != '_lifecycle') { // create object to store properties const writeObject = new Object(); writeObject.blocknumber = blockNumber; From 98028c7da006289d0731ce162a9620cf25c80e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baran=20K=C4=B1l=C4=B1=C3=A7?= Date: Wed, 29 Sep 2021 12:51:31 +0300 Subject: [PATCH 007/106] Fix ERC1155 chaincode indeterminism caused by iterating maps in Go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions BatchTransferFrom and BatchTransferFromMultiRecipient in ERC1155 sometimes give the error `ProposalResponsePayloads do not match`. This happens because iterating maps in Go is not deterministic. As a solution, I copied the keys of the map and sorted them and iterated over the sorted keys. Signed-off-by: Baran Kılıç --- .../chaincode-go/chaincode/contract.go | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/token-erc-1155/chaincode-go/chaincode/contract.go b/token-erc-1155/chaincode-go/chaincode/contract.go index dfe1c3cb..a86c9c9b 100644 --- a/token-erc-1155/chaincode-go/chaincode/contract.go +++ b/token-erc-1155/chaincode-go/chaincode/contract.go @@ -9,6 +9,7 @@ package chaincode import ( "encoding/json" "fmt" + "sort" "strconv" "strings" @@ -101,6 +102,8 @@ type URI struct { ID uint64 `json:"id"` } +// To represents recipient address +// ID represents token ID type ToID struct { To string ID uint64 @@ -160,8 +163,12 @@ func (s *SmartContract) MintBatch(ctx contractapi.TransactionContextInterface, a amountToSend[ids[i]] += amounts[i] } + // Copy the map keys and sort it. This is necessary because iterating maps in Go is not deterministic + amountToSendKeys := sortedKeys(amountToSend) + // Mint tokens - for id, amount := range amountToSend { + for _, id := range amountToSendKeys { + amount := amountToSend[id] err = mintHelper(ctx, operator, account, id, amount) if err != nil { return err @@ -328,8 +335,12 @@ func (s *SmartContract) BatchTransferFrom(ctx contractapi.TransactionContextInte amountToSend[ids[i]] += amounts[i] } + // Copy the map keys and sort it. This is necessary because iterating maps in Go is not deterministic + amountToSendKeys := sortedKeys(amountToSend) + // Deposit the funds to the recipient address - for id, amount := range amountToSend { + for _, id := range amountToSendKeys { + amount := amountToSend[id] err = addBalance(ctx, sender, recipient, id, amount) if err != nil { return err @@ -385,12 +396,17 @@ func (s *SmartContract) BatchTransferFromMultiRecipient(ctx contractapi.Transact amountToSend[ToID{recipients[i], ids[i]}] += amounts[i] } + // Copy the map keys and sort it. This is necessary because iterating maps in Go is not deterministic + amountToSendKeys := sortedKeysToID(amountToSend) + // Deposit the funds to the recipient addresses - for key, amount := range amountToSend { + for _, key := range amountToSendKeys { if key.To == "0x0" { return fmt.Errorf("transfer to the zero address") } + amount := amountToSend[key] + err = addBalance(ctx, sender, key.To, key.ID, amount) if err != nil { return err @@ -665,8 +681,12 @@ func removeBalance(ctx contractapi.TransactionContextInterface, sender string, i necessaryFunds[ids[i]] += amounts[i] } + // Copy the map keys and sort it. This is necessary because iterating maps in Go is not deterministic + necessaryFundsKeys := sortedKeys(necessaryFunds) + // Check whether the sender has the necessary funds and withdraw them from the account - for tokenId, neededAmount := range necessaryFunds { + for _, tokenId := range necessaryFundsKeys { + neededAmount := necessaryFunds[tokenId] idString := strconv.FormatUint(uint64(tokenId), 10) var partialBalance uint64 @@ -806,3 +826,36 @@ func balanceOfHelper(ctx contractapi.TransactionContextInterface, account string return balance, nil } + +// Returns the sorted slice ([]uint64) copied from the keys of map[uint64]uint64 +func sortedKeys(m map[uint64]uint64) []uint64 { + // Copy map keys to slice + keys := make([]uint64, len(m)) + i := 0 + for k := range m { + keys[i] = k + i++ + } + // Sort the slice + sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] }) + return keys +} + +// Returns the sorted slice ([]ToID) copied from the keys of map[ToID]uint64 +func sortedKeysToID(m map[ToID]uint64) []ToID { + // Copy map keys to slice + keys := make([]ToID, len(m)) + i := 0 + for k := range m { + keys[i] = k + i++ + } + // Sort the slice first according to ID if equal then sort by recipient ("To" field) + sort.Slice(keys, func(i, j int) bool { + if keys[i].ID != keys[j].ID { + return keys[i].To < keys[j].To + } + return keys[i].ID < keys[j].ID + }) + return keys +} From ee959a2eb0a9b1a9066560f876df5ba4e1e27c2e Mon Sep 17 00:00:00 2001 From: denyeart Date: Fri, 1 Oct 2021 04:16:56 -0400 Subject: [PATCH 008/106] Update to Go 1.16.7 (#491) Update Go to 1.16.7 and run "go mod tidy" to clean up go modules in samples. Signed-off-by: David Enyeart --- asset-transfer-abac/chaincode-go/go.mod | 4 +- asset-transfer-abac/chaincode-go/go.sum | 36 +-- asset-transfer-basic/application-go/go.mod | 6 +- asset-transfer-basic/application-go/go.sum | 95 ++------ .../chaincode-external/go.sum | 1 - asset-transfer-basic/chaincode-go/go.mod | 4 +- asset-transfer-basic/chaincode-go/go.sum | 30 ++- .../chaincode-go/go.mod | 4 +- .../chaincode-go/go.sum | 29 ++- .../chaincode-go/go.mod | 5 +- .../chaincode-go/go.sum | 51 ++--- .../chaincode-go/go.mod | 4 +- .../chaincode-go/go.sum | 36 +-- auction-dutch/chaincode-go/go.mod | 5 +- auction-dutch/chaincode-go/go.sum | 24 +- auction-simple/chaincode-go/go.mod | 4 +- auction-simple/chaincode-go/go.sum | 36 +-- chaincode/abstore/go/go.sum | 4 - chaincode/fabcar/external/go.sum | 1 - chaincode/fabcar/go/go.sum | 1 - chaincode/marbles02/go/go.sum | 8 - chaincode/marbles02_private/go/go.mod | 5 +- chaincode/marbles02_private/go/go.sum | 28 +++ chaincode/sacc/go.sum | 5 - ci/azure-pipelines.yml | 3 +- ci/templates/fabcar/azure-pipelines-go.yml | 4 +- .../organization/digibank/contract-go/go.mod | 4 +- .../organization/digibank/contract-go/go.sum | 32 ++- .../organization/digibank/contract-go/main.go | 2 +- .../magnetocorp/contract-go/go.mod | 4 +- .../magnetocorp/contract-go/go.sum | 32 ++- .../magnetocorp/contract-go/main.go | 2 +- fabcar/go/go.sum | 216 +++++++++++++----- high-throughput/application-go/go.mod | 6 +- high-throughput/application-go/go.sum | 44 ++-- high-throughput/chaincode-go/go.mod | 4 +- high-throughput/chaincode-go/go.sum | 41 ++-- interest_rate_swaps/chaincode/go.sum | 5 - token-erc-1155/chaincode-go/go.mod | 7 +- token-erc-1155/chaincode-go/go.sum | 25 +- token-erc-20/chaincode-go/go.mod | 4 +- token-erc-20/chaincode-go/go.sum | 29 ++- token-utxo/chaincode-go/go.mod | 4 +- token-utxo/chaincode-go/go.sum | 29 ++- 44 files changed, 510 insertions(+), 413 deletions(-) diff --git a/asset-transfer-abac/chaincode-go/go.mod b/asset-transfer-abac/chaincode-go/go.mod index 136d7940..6730b91d 100644 --- a/asset-transfer-abac/chaincode-go/go.mod +++ b/asset-transfer-abac/chaincode-go/go.mod @@ -4,5 +4,7 @@ go 1.15 require ( github.com/hyperledger/fabric-contract-api-go v1.1.1 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect ) diff --git a/asset-transfer-abac/chaincode-go/go.sum b/asset-transfer-abac/chaincode-go/go.sum index 1af2f6fa..0884bc65 100644 --- a/asset-transfer-abac/chaincode-go/go.sum +++ b/asset-transfer-abac/chaincode-go/go.sum @@ -13,6 +13,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= @@ -34,6 +35,7 @@ github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -55,9 +57,11 @@ github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0L github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -66,6 +70,7 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= @@ -84,6 +89,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -93,41 +99,39 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -135,11 +139,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -152,6 +155,7 @@ google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/asset-transfer-basic/application-go/go.mod b/asset-transfer-basic/application-go/go.mod index 6827d4d1..d7c5f637 100644 --- a/asset-transfer-basic/application-go/go.mod +++ b/asset-transfer-basic/application-go/go.mod @@ -4,5 +4,9 @@ go 1.14 require ( github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/asset-transfer-basic/application-go/go.sum b/asset-transfer-basic/application-go/go.sum index 7050b1cf..9d189073 100644 --- a/asset-transfer-basic/application-go/go.sum +++ b/asset-transfer-basic/application-go/go.sum @@ -1,15 +1,16 @@ bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -18,8 +19,6 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= -github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ= -github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiKw= github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= @@ -41,48 +40,35 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93 h1:qdfmdGwtm13OVx+AxguOWUTbgmXGn2TbdUHipo3chMg= -github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno= -github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hyperledger/fabric-config v0.0.5 h1:khRkm8U9Ghdg8VmZfptgzCFlCzrka8bPfUkM+/j6Zlg= github.com/hyperledger/fabric-config v0.0.5/go.mod h1:YpITBI/+ZayA3XWY5lF302K7PAsFYjEEPM/zr3hegA8= github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324= github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= -github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85 h1:bNgEcCg5NVRWs/T+VUEfhgh5Olx/N4VB+0+ybW+oSuA= -github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 h1:SEbB3yH4ISTGRifDamYXAst36gO2kM855ndMJlsv+pc= github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f h1:eAkJx0+8PBbfP6xZxVRD2agk9W7oDbqllxO+ERgnKJk= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta2 h1:FBYygns0Qga+mQ4PXycyTU5m4N9KAZM+Ttf7agiV7M8= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta2/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta3.0.20201006151309-9c426dcc5096 h1:veml7LmfavSHqF8w8z/PGGlfdXvmx5SstQIH6Nyy87c= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta3.0.20201006151309-9c426dcc5096/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU= github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 h1:cfDo/5ovUZf2dCz08fznUxxVYEWAT4yKJcAh9b+K9Mk= github.com/hyperledger/fabric-sdk-go v1.0.0-rc1/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -97,22 +83,19 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.7.6 h1:U+1DqNen04MdEPgFiIwdOUiqZ8qPa37xgogX/sd3+54= -github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27/go.mod h1:WCBAbTOdfhHhz7YXujeZMF7owC4tPb1naKFsgfUISjo= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238 h1:+MZW2uvHgN8kYvksEN3f7eFL2wpzk0GxmlFsMybWc7E= -github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -122,12 +105,11 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/pelletier/go-toml v1.1.0 h1:cmiOvKzEunMsAxyhXSzpL5Q1CRKpVv0KQsnAIcSEVYM= -github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -136,54 +118,36 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 h1:osmNoEW2SCW3L7EX0km2LYM8HKpNWRiouxjE3XHkyGc= -github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f h1:c9M4CCa6g8WURSsbrl3lb/w/G1Z5xZpYvhhjdcVDOkE= -github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/spf13/afero v1.1.0 h1:bopulORc2JeYaxfHLvJa5NzxviA9PoWhpiiJkru7Ji4= -github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.3.1 h1:GPTpEAuNr98px18yNQ66JllNil98wfRZ/5Ukny8FeQA= github.com/spf13/afero v1.3.1/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= -github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig= -github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso= -github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.1.1 h1:/8JBRFO4eoHu1TmpsLgNBq1CQgRUg4GolYlEFieqJgo= github.com/spf13/viper v1.1.1/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= @@ -193,7 +157,7 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -202,12 +166,10 @@ github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8F github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg= github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -216,44 +178,39 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -262,11 +219,10 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -274,22 +230,21 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8= -google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/asset-transfer-basic/chaincode-external/go.sum b/asset-transfer-basic/chaincode-external/go.sum index a159a45f..5a92905b 100644 --- a/asset-transfer-basic/chaincode-external/go.sum +++ b/asset-transfer-basic/chaincode-external/go.sum @@ -139,7 +139,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/asset-transfer-basic/chaincode-go/go.mod b/asset-transfer-basic/chaincode-go/go.mod index ad2bb36c..31ab687b 100644 --- a/asset-transfer-basic/chaincode-go/go.mod +++ b/asset-transfer-basic/chaincode-go/go.mod @@ -8,5 +8,7 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect ) diff --git a/asset-transfer-basic/chaincode-go/go.sum b/asset-transfer-basic/chaincode-go/go.sum index a73be6ec..8b6fa693 100644 --- a/asset-transfer-basic/chaincode-go/go.sum +++ b/asset-transfer-basic/chaincode-go/go.sum @@ -99,41 +99,39 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -141,11 +139,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -161,7 +158,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/asset-transfer-ledger-queries/chaincode-go/go.mod b/asset-transfer-ledger-queries/chaincode-go/go.mod index 56baff95..e060e458 100644 --- a/asset-transfer-ledger-queries/chaincode-go/go.mod +++ b/asset-transfer-ledger-queries/chaincode-go/go.mod @@ -6,5 +6,7 @@ require ( github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect ) diff --git a/asset-transfer-ledger-queries/chaincode-go/go.sum b/asset-transfer-ledger-queries/chaincode-go/go.sum index a65cda85..9bbd040e 100644 --- a/asset-transfer-ledger-queries/chaincode-go/go.sum +++ b/asset-transfer-ledger-queries/chaincode-go/go.sum @@ -100,41 +100,39 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -142,11 +140,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-private-data/chaincode-go/go.mod b/asset-transfer-private-data/chaincode-go/go.mod index 4f262bf1..31f32b5e 100644 --- a/asset-transfer-private-data/chaincode-go/go.mod +++ b/asset-transfer-private-data/chaincode-go/go.mod @@ -16,7 +16,10 @@ require ( github.com/rogpeppe/go-internal v1.6.0 // indirect github.com/stretchr/testify v1.5.1 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986 // indirect google.golang.org/grpc v1.30.0 // indirect google.golang.org/protobuf v1.25.0 diff --git a/asset-transfer-private-data/chaincode-go/go.sum b/asset-transfer-private-data/chaincode-go/go.sum index 7ddfb1de..35e65707 100644 --- a/asset-transfer-private-data/chaincode-go/go.sum +++ b/asset-transfer-private-data/chaincode-go/go.sum @@ -25,37 +25,30 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg= github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg= github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE= github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.9.0 h1:eZR0DuEgVLfeIb1zIKt3bT4YovIMf9O9LXQeCZLXpqE= github.com/gobuffalo/envy v1.9.0/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM= github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI= github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -73,14 +66,12 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212 h1:1i4lnpV8BDgKOLi1hgElfBqdHXjXieSuj8629mwBZ8o= github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc= github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a h1:KoFw2HnRfW+EItMP0zvUUl1FGzDb/7O0ov7uXZffQok= github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc= github.com/hyperledger/fabric-contract-api-go v1.1.0 h1:K9uucl/6eX3NF0/b+CGIiO1IPm1VYQxBkpnVGJur2S4= github.com/hyperledger/fabric-contract-api-go v1.1.0/go.mod h1:nHWt0B45fK53owcFpLtAe8DH0Q5P068mnzkNXMPSL7E= github.com/hyperledger/fabric-protos-go v0.0.0-20190919234611-2a87503ac7c9/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= -github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e h1:9PS5iezHk/j7XriSlNuSQILyCOfcZ9wZ3/PiucmSE8E= github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 h1:SEbB3yH4ISTGRifDamYXAst36gO2kM855ndMJlsv+pc= github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= @@ -99,7 +90,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= @@ -110,7 +100,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.0 h1:IZRgg4sfrDH7nsAD1Y/Nwj+GzIfEwpJSLjCaNC3SbsI= @@ -132,7 +121,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -141,19 +129,18 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -162,17 +149,14 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -180,16 +164,13 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8= -golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -199,28 +180,24 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986 h1:10ohwcLf82I55O/aQxYqmWKoOdNbQTYYComeP1KDOS4= google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -234,7 +211,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= @@ -245,7 +221,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/asset-transfer-secured-agreement/chaincode-go/go.mod b/asset-transfer-secured-agreement/chaincode-go/go.mod index 8f945cfe..4662158f 100644 --- a/asset-transfer-secured-agreement/chaincode-go/go.mod +++ b/asset-transfer-secured-agreement/chaincode-go/go.mod @@ -6,5 +6,7 @@ require ( github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-chaincode-go v0.0.0-20200128192331-2d899240a7ed github.com/hyperledger/fabric-contract-api-go v1.0.0 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect ) diff --git a/asset-transfer-secured-agreement/chaincode-go/go.sum b/asset-transfer-secured-agreement/chaincode-go/go.sum index fa38d6ce..b8bb8d34 100644 --- a/asset-transfer-secured-agreement/chaincode-go/go.sum +++ b/asset-transfer-secured-agreement/chaincode-go/go.sum @@ -12,6 +12,7 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= @@ -33,6 +34,7 @@ github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wK github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -55,9 +57,11 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -66,6 +70,7 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= @@ -83,6 +88,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -92,41 +98,39 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -135,11 +139,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -151,6 +154,7 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/auction-dutch/chaincode-go/go.mod b/auction-dutch/chaincode-go/go.mod index 1b9b2bf0..0eb59b96 100644 --- a/auction-dutch/chaincode-go/go.mod +++ b/auction-dutch/chaincode-go/go.mod @@ -7,7 +7,8 @@ require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20201119163726-f8ef75b17719 github.com/hyperledger/fabric-contract-api-go v1.1.1 github.com/hyperledger/fabric-protos-go v0.0.0-20210127161553-4f432a78f286 - golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect - golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/auction-dutch/chaincode-go/go.sum b/auction-dutch/chaincode-go/go.sum index fa4b84fb..8b1f4390 100644 --- a/auction-dutch/chaincode-go/go.sum +++ b/auction-dutch/chaincode-go/go.sum @@ -111,21 +111,26 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -133,9 +138,11 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= @@ -145,6 +152,11 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/auction-simple/chaincode-go/go.mod b/auction-simple/chaincode-go/go.mod index a6309a1e..ba8272cf 100644 --- a/auction-simple/chaincode-go/go.mod +++ b/auction-simple/chaincode-go/go.mod @@ -5,5 +5,7 @@ go 1.15 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20200728190242-9b3ae92d8664 github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect ) diff --git a/auction-simple/chaincode-go/go.sum b/auction-simple/chaincode-go/go.sum index 707315c7..4e88963d 100644 --- a/auction-simple/chaincode-go/go.sum +++ b/auction-simple/chaincode-go/go.sum @@ -13,6 +13,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= @@ -34,6 +35,7 @@ github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -56,9 +58,11 @@ github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0L github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -67,6 +71,7 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= @@ -85,6 +90,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -94,41 +100,39 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -136,11 +140,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -153,6 +156,7 @@ google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/chaincode/abstore/go/go.sum b/chaincode/abstore/go/go.sum index 12dd961a..5a92905b 100644 --- a/chaincode/abstore/go/go.sum +++ b/chaincode/abstore/go/go.sum @@ -56,7 +56,6 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -89,7 +88,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -137,12 +135,10 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/chaincode/fabcar/external/go.sum b/chaincode/fabcar/external/go.sum index a159a45f..5a92905b 100644 --- a/chaincode/fabcar/external/go.sum +++ b/chaincode/fabcar/external/go.sum @@ -139,7 +139,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/chaincode/fabcar/go/go.sum b/chaincode/fabcar/go/go.sum index a159a45f..5a92905b 100644 --- a/chaincode/fabcar/go/go.sum +++ b/chaincode/fabcar/go/go.sum @@ -139,7 +139,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/chaincode/marbles02/go/go.sum b/chaincode/marbles02/go/go.sum index 66ba37b6..afd17d88 100644 --- a/chaincode/marbles02/go/go.sum +++ b/chaincode/marbles02/go/go.sum @@ -1,8 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -28,7 +26,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -41,7 +38,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -54,7 +50,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -66,16 +61,13 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/chaincode/marbles02_private/go/go.mod b/chaincode/marbles02_private/go/go.mod index 86745398..1f91ffc3 100644 --- a/chaincode/marbles02_private/go/go.mod +++ b/chaincode/marbles02_private/go/go.mod @@ -2,4 +2,7 @@ module github.com/hyperledger/fabric-samples/chaincode/marbles02_private/go go 1.13 -require github.com/hyperledger/fabric-contract-api-go v1.1.0 +require ( + github.com/hyperledger/fabric-contract-api-go v1.1.0 + golang.org/x/tools v0.1.5 // indirect +) diff --git a/chaincode/marbles02_private/go/go.sum b/chaincode/marbles02_private/go/go.sum index 653dbb08..8ea59aab 100644 --- a/chaincode/marbles02_private/go/go.sum +++ b/chaincode/marbles02_private/go/go.sum @@ -13,6 +13,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= @@ -34,6 +35,7 @@ github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -55,9 +57,11 @@ github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0L github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -66,6 +70,7 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= @@ -84,6 +89,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -93,34 +99,55 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= @@ -129,6 +156,7 @@ google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/chaincode/sacc/go.sum b/chaincode/sacc/go.sum index da5b5719..afd17d88 100644 --- a/chaincode/sacc/go.sum +++ b/chaincode/sacc/go.sum @@ -1,5 +1,4 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -39,7 +38,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -52,7 +50,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -64,9 +61,7 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 6b1908f1..2b8a0a27 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -5,11 +5,12 @@ trigger: - main - release-1.4 + - release-2.2 variables: FABRIC_VERSION: 2.4 GO_BIN: $(Build.Repository.LocalPath)/bin - GO_VER: 1.14.6 + GO_VER: 1.16.7 NODE_VER: 12.x PATH: $(Build.Repository.LocalPath)/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin diff --git a/ci/templates/fabcar/azure-pipelines-go.yml b/ci/templates/fabcar/azure-pipelines-go.yml index 6e1562c6..c2fafd1b 100644 --- a/ci/templates/fabcar/azure-pipelines-go.yml +++ b/ci/templates/fabcar/azure-pipelines-go.yml @@ -7,9 +7,9 @@ steps: workingDirectory: fabcar displayName: Start Fabric - task: GoTool@0 - displayName: 'Use Go 1.14.2' + displayName: 'Use Go 1.16.7' inputs: - version: '1.14.2' + version: '1.16.7' - task: Go@0 displayName: 'go build' inputs: diff --git a/commercial-paper/organization/digibank/contract-go/go.mod b/commercial-paper/organization/digibank/contract-go/go.mod index 3b2b8431..3c2ae75e 100644 --- a/commercial-paper/organization/digibank/contract-go/go.mod +++ b/commercial-paper/organization/digibank/contract-go/go.mod @@ -7,7 +7,9 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/mailru/easyjson v0.7.0 // indirect github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect google.golang.org/grpc v1.24.0 // indirect ) diff --git a/commercial-paper/organization/digibank/contract-go/go.sum b/commercial-paper/organization/digibank/contract-go/go.sum index 8a4dbd4c..5d3d13ee 100644 --- a/commercial-paper/organization/digibank/contract-go/go.sum +++ b/commercial-paper/organization/digibank/contract-go/go.sum @@ -91,7 +91,6 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -103,19 +102,18 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -125,15 +123,13 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= -golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -141,13 +137,13 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -157,11 +153,10 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -181,7 +176,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/commercial-paper/organization/digibank/contract-go/main.go b/commercial-paper/organization/digibank/contract-go/main.go index 002c4f96..e6e079ed 100644 --- a/commercial-paper/organization/digibank/contract-go/main.go +++ b/commercial-paper/organization/digibank/contract-go/main.go @@ -8,7 +8,7 @@ import ( "fmt" "github.com/hyperledger/fabric-contract-api-go/contractapi" - "github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go/commercial-paper" + commercialpaper "github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/contract-go/commercial-paper" ) func main() { diff --git a/commercial-paper/organization/magnetocorp/contract-go/go.mod b/commercial-paper/organization/magnetocorp/contract-go/go.mod index 24f86632..147604fd 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/go.mod +++ b/commercial-paper/organization/magnetocorp/contract-go/go.mod @@ -7,7 +7,9 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/mailru/easyjson v0.7.0 // indirect github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect google.golang.org/grpc v1.24.0 // indirect ) diff --git a/commercial-paper/organization/magnetocorp/contract-go/go.sum b/commercial-paper/organization/magnetocorp/contract-go/go.sum index 8a4dbd4c..5d3d13ee 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/go.sum +++ b/commercial-paper/organization/magnetocorp/contract-go/go.sum @@ -91,7 +91,6 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -103,19 +102,18 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -125,15 +123,13 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= -golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -141,13 +137,13 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -157,11 +153,10 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -181,7 +176,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/commercial-paper/organization/magnetocorp/contract-go/main.go b/commercial-paper/organization/magnetocorp/contract-go/main.go index ee83834d..98606c1b 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/main.go +++ b/commercial-paper/organization/magnetocorp/contract-go/main.go @@ -8,7 +8,7 @@ import ( "fmt" "github.com/hyperledger/fabric-contract-api-go/contractapi" - "github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go/commercial-paper" + commercialpaper "github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/contract-go/commercial-paper" ) func main() { diff --git a/fabcar/go/go.sum b/fabcar/go/go.sum index 4d2133cc..2cbdd369 100644 --- a/fabcar/go/go.sum +++ b/fabcar/go/go.sum @@ -1,126 +1,238 @@ +bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ= -github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= +github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= +github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiKw= +github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= +github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= +github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93 h1:qdfmdGwtm13OVx+AxguOWUTbgmXGn2TbdUHipo3chMg= -github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno= -github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hyperledger/fabric-config v0.0.5 h1:khRkm8U9Ghdg8VmZfptgzCFlCzrka8bPfUkM+/j6Zlg= +github.com/hyperledger/fabric-config v0.0.5/go.mod h1:YpITBI/+ZayA3XWY5lF302K7PAsFYjEEPM/zr3hegA8= github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324= github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= -github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85 h1:bNgEcCg5NVRWs/T+VUEfhgh5Olx/N4VB+0+ybW+oSuA= -github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f h1:eAkJx0+8PBbfP6xZxVRD2agk9W7oDbqllxO+ERgnKJk= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta2 h1:FBYygns0Qga+mQ4PXycyTU5m4N9KAZM+Ttf7agiV7M8= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta2/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= +github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= +github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 h1:SEbB3yH4ISTGRifDamYXAst36gO2kM855ndMJlsv+pc= +github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= +github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 h1:cfDo/5ovUZf2dCz08fznUxxVYEWAT4yKJcAh9b+K9Mk= +github.com/hyperledger/fabric-sdk-go v1.0.0-rc1/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= +github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.7.6 h1:U+1DqNen04MdEPgFiIwdOUiqZ8qPa37xgogX/sd3+54= -github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= +github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27/go.mod h1:WCBAbTOdfhHhz7YXujeZMF7owC4tPb1naKFsgfUISjo= -github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238 h1:+MZW2uvHgN8kYvksEN3f7eFL2wpzk0GxmlFsMybWc7E= -github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pelletier/go-toml v1.1.0 h1:cmiOvKzEunMsAxyhXSzpL5Q1CRKpVv0KQsnAIcSEVYM= -github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= +github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 h1:osmNoEW2SCW3L7EX0km2LYM8HKpNWRiouxjE3XHkyGc= -github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f h1:c9M4CCa6g8WURSsbrl3lb/w/G1Z5xZpYvhhjdcVDOkE= -github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/spf13/afero v1.1.0 h1:bopulORc2JeYaxfHLvJa5NzxviA9PoWhpiiJkru7Ji4= -github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= -github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig= -github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso= -github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/spf13/afero v1.3.1 h1:GPTpEAuNr98px18yNQ66JllNil98wfRZ/5Ukny8FeQA= +github.com/spf13/afero v1.3.1/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.1.1 h1:/8JBRFO4eoHu1TmpsLgNBq1CQgRUg4GolYlEFieqJgo= +github.com/spf13/viper v1.1.1/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= +github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e h1:mvOa4+/DXStR4ZXOks/UsjeFdn5O5JpLUtzqk9U8xXw= +github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8= +github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg= +github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d h1:XB2jc5XQ9uhizGTS2vWcN01bc4dI6z3C4KY5MQm8SS8= -google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/high-throughput/application-go/go.mod b/high-throughput/application-go/go.mod index bf6f418d..36fd191c 100644 --- a/high-throughput/application-go/go.mod +++ b/high-throughput/application-go/go.mod @@ -4,5 +4,9 @@ go 1.14 require ( github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/high-throughput/application-go/go.sum b/high-throughput/application-go/go.sum index 8fb95fae..9d189073 100644 --- a/high-throughput/application-go/go.sum +++ b/high-throughput/application-go/go.sum @@ -1,10 +1,12 @@ bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -38,6 +40,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -52,10 +55,12 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hyperledger/fabric-config v0.0.5 h1:khRkm8U9Ghdg8VmZfptgzCFlCzrka8bPfUkM+/j6Zlg= github.com/hyperledger/fabric-config v0.0.5/go.mod h1:YpITBI/+ZayA3XWY5lF302K7PAsFYjEEPM/zr3hegA8= @@ -64,8 +69,6 @@ github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDW github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 h1:SEbB3yH4ISTGRifDamYXAst36gO2kM855ndMJlsv+pc= github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta3.0.20201006151309-9c426dcc5096 h1:veml7LmfavSHqF8w8z/PGGlfdXvmx5SstQIH6Nyy87c= -github.com/hyperledger/fabric-sdk-go v1.0.0-beta3.0.20201006151309-9c426dcc5096/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU= github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 h1:cfDo/5ovUZf2dCz08fznUxxVYEWAT4yKJcAh9b+K9Mk= github.com/hyperledger/fabric-sdk-go v1.0.0-rc1/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -78,9 +81,12 @@ github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCy github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -99,7 +105,9 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= @@ -149,7 +157,7 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -162,7 +170,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -171,8 +178,8 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -180,31 +187,30 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -213,11 +219,10 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= @@ -234,8 +239,11 @@ google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/high-throughput/chaincode-go/go.mod b/high-throughput/chaincode-go/go.mod index 5e7ac574..dd5fccdd 100644 --- a/high-throughput/chaincode-go/go.mod +++ b/high-throughput/chaincode-go/go.mod @@ -5,6 +5,8 @@ go 1.12 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect ) diff --git a/high-throughput/chaincode-go/go.sum b/high-throughput/chaincode-go/go.sum index 55b6f931..2e2fa959 100644 --- a/high-throughput/chaincode-go/go.sum +++ b/high-throughput/chaincode-go/go.sum @@ -1,8 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -28,51 +26,42 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -80,27 +69,23 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/interest_rate_swaps/chaincode/go.sum b/interest_rate_swaps/chaincode/go.sum index 21d2908d..afd17d88 100644 --- a/interest_rate_swaps/chaincode/go.sum +++ b/interest_rate_swaps/chaincode/go.sum @@ -38,7 +38,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -48,11 +47,9 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -64,9 +61,7 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= diff --git a/token-erc-1155/chaincode-go/go.mod b/token-erc-1155/chaincode-go/go.mod index 4b49a6f6..c78f40ae 100644 --- a/token-erc-1155/chaincode-go/go.mod +++ b/token-erc-1155/chaincode-go/go.mod @@ -2,4 +2,9 @@ module erc1155 go 1.16 -require github.com/hyperledger/fabric-contract-api-go v1.1.1 +require ( + github.com/hyperledger/fabric-contract-api-go v1.1.1 + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect +) diff --git a/token-erc-1155/chaincode-go/go.sum b/token-erc-1155/chaincode-go/go.sum index 8ff9fad9..0884bc65 100644 --- a/token-erc-1155/chaincode-go/go.sum +++ b/token-erc-1155/chaincode-go/go.sum @@ -99,35 +99,54 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/token-erc-20/chaincode-go/go.mod b/token-erc-20/chaincode-go/go.mod index c08954d3..c29e7850 100644 --- a/token-erc-20/chaincode-go/go.mod +++ b/token-erc-20/chaincode-go/go.mod @@ -4,5 +4,7 @@ go 1.14 require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect ) diff --git a/token-erc-20/chaincode-go/go.sum b/token-erc-20/chaincode-go/go.sum index 374a50b1..8b6fa693 100644 --- a/token-erc-20/chaincode-go/go.sum +++ b/token-erc-20/chaincode-go/go.sum @@ -99,41 +99,39 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -141,11 +139,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/token-utxo/chaincode-go/go.mod b/token-utxo/chaincode-go/go.mod index 5ace7073..0674345b 100644 --- a/token-utxo/chaincode-go/go.mod +++ b/token-utxo/chaincode-go/go.mod @@ -4,5 +4,7 @@ go 1.14 require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.0 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/tools v0.1.5 // indirect ) diff --git a/token-utxo/chaincode-go/go.sum b/token-utxo/chaincode-go/go.sum index 374a50b1..8b6fa693 100644 --- a/token-utxo/chaincode-go/go.sum +++ b/token-utxo/chaincode-go/go.sum @@ -99,41 +99,39 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -141,11 +139,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= From 56a1bf3e194b400a0e3c498a383a74247f54ceb3 Mon Sep 17 00:00:00 2001 From: sapthasurendran <48531319+sapthasurendran@users.noreply.github.com> Date: Wed, 6 Oct 2021 18:03:29 +0530 Subject: [PATCH 009/106] * Made consistent lint command (#495) * Removed global install of lint modules * Fixed Lint Issues Signed-off-by: sapthasurendran added lint script forapplication javascript Signed-off-by: sapthasurendran updated lint command for chaincode javascript Signed-off-by: sapthasurendran updated lint script Signed-off-by: sapthasurendran remove installing dependencies Signed-off-by: sapthasurendran added lint script to js projects Signed-off-by: sapthasurendran added more lint scripts Signed-off-by: sapthasurendran added more lint scripts Signed-off-by: sapthasurendran added missing npm lint command Signed-off-by: sapthasurendran added missing eslint npm module Signed-off-by: sapthasurendran Fix missing npm lint command Signed-off-by: sapthasurendran added missing eslint npm module to auction-simple javascctipt app Signed-off-by: sapthasurendran added eslint npm module Signed-off-by: sapthasurendran added eslint dependency Signed-off-by: sapthasurendran added eslint dependency Signed-off-by: sapthasurendran added eslint dependency Signed-off-by: sapthasurendran Single command for ts js lint Signed-off-by: sapthasurendran Fix or condition in lint.sh Signed-off-by: sapthasurendran --- .../application-javascript/package.json | 7 +++++++ .../chaincode-javascript/package.json | 2 +- .../chaincode-typescript/src/assetTransfer.ts | 2 +- .../application-javascript/package.json | 6 ++++++ .../application-javascript/package.json | 6 ++++++ .../chaincode-javascript/package.json | 6 +++++- .../application-javascript/package.json | 6 ++++++ .../application-javascript/package.json | 6 ++++++ auction-dutch/application-javascript/package.json | 4 ++++ .../application-javascript/package.json | 6 ++++++ ci/azure-pipelines.yml | 2 -- ci/scripts/lint.sh | 15 +++++---------- 12 files changed, 53 insertions(+), 15 deletions(-) diff --git a/asset-transfer-basic/application-javascript/package.json b/asset-transfer-basic/application-javascript/package.json index bab813d1..9e11390c 100644 --- a/asset-transfer-basic/application-javascript/package.json +++ b/asset-transfer-basic/application-javascript/package.json @@ -6,11 +6,18 @@ "node": ">=12", "npm": ">=5" }, + "scripts": { + "lint": "eslint *.js", + "pretest": "npm run lint" + }, "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", "dependencies": { "fabric-ca-client": "^2.2.4", "fabric-network": "^2.2.4" + }, + "devDependencies": { + "eslint": "^7.32.0" } } diff --git a/asset-transfer-basic/chaincode-javascript/package.json b/asset-transfer-basic/chaincode-javascript/package.json index 430f9f61..6a44f07d 100644 --- a/asset-transfer-basic/chaincode-javascript/package.json +++ b/asset-transfer-basic/chaincode-javascript/package.json @@ -8,7 +8,7 @@ "npm": ">=5" }, "scripts": { - "lint": "eslint .", + "lint": "eslint *.js */**.js", "pretest": "npm run lint", "test": "nyc mocha --recursive", "start": "fabric-chaincode-node start" diff --git a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts index db2f9a9e..80809475 100644 --- a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts +++ b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts @@ -2,9 +2,9 @@ * SPDX-License-Identifier: Apache-2.0 */ // Deterministic JSON.stringify() +import {Context, Contract, Info, Returns, Transaction} from 'fabric-contract-api'; import * as stringify from 'json-stringify-deterministic'; import * as sortKeysRecursive from 'sort-keys-recursive'; -import {Context, Contract, Info, Returns, Transaction} from 'fabric-contract-api'; import {Asset} from './asset'; @Info({title: 'AssetTransfer', description: 'Smart contract for trading assets'}) diff --git a/asset-transfer-events/application-javascript/package.json b/asset-transfer-events/application-javascript/package.json index 2767aede..91eb4b40 100644 --- a/asset-transfer-events/application-javascript/package.json +++ b/asset-transfer-events/application-javascript/package.json @@ -9,8 +9,14 @@ "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", + "scripts": { + "lint": "eslint *.js" + }, "dependencies": { "fabric-ca-client": "^2.2.2", "fabric-network": "^2.2.2" + }, + "devDependencies": { + "eslint": "^7.32.0" } } diff --git a/asset-transfer-ledger-queries/application-javascript/package.json b/asset-transfer-ledger-queries/application-javascript/package.json index f06a831f..8d92146a 100644 --- a/asset-transfer-ledger-queries/application-javascript/package.json +++ b/asset-transfer-ledger-queries/application-javascript/package.json @@ -9,8 +9,14 @@ "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", + "scripts": { + "lint": "eslint *.js" + }, "dependencies": { "fabric-ca-client": "^2.2.4", "fabric-network": "^2.2.4" + }, + "devDependencies": { + "eslint": "^7.32.0" } } diff --git a/asset-transfer-ledger-queries/chaincode-javascript/package.json b/asset-transfer-ledger-queries/chaincode-javascript/package.json index 0427b5c8..6eabb59b 100644 --- a/asset-transfer-ledger-queries/chaincode-javascript/package.json +++ b/asset-transfer-ledger-queries/chaincode-javascript/package.json @@ -8,12 +8,16 @@ "npm": ">=5.3.0" }, "scripts": { - "start": "fabric-chaincode-node start" + "start": "fabric-chaincode-node start", + "lint": "eslint *.js */**.js" }, "engine-strict": true, "license": "Apache-2.0", "dependencies": { "fabric-contract-api": "^2.0.0", "fabric-shim": "^2.0.0" + }, + "devDependencies": { + "eslint": "^7.32.0" } } diff --git a/asset-transfer-sbe/application-javascript/package.json b/asset-transfer-sbe/application-javascript/package.json index aa8cefb5..39b98ceb 100644 --- a/asset-transfer-sbe/application-javascript/package.json +++ b/asset-transfer-sbe/application-javascript/package.json @@ -9,8 +9,14 @@ "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", + "scripts": { + "lint": "eslint *.js" + }, "dependencies": { "fabric-ca-client": "^2.2.4", "fabric-network": "^2.2.4" + }, + "devDependencies": { + "eslint": "^7.32.0" } } diff --git a/asset-transfer-secured-agreement/application-javascript/package.json b/asset-transfer-secured-agreement/application-javascript/package.json index d3424562..59f225c7 100644 --- a/asset-transfer-secured-agreement/application-javascript/package.json +++ b/asset-transfer-secured-agreement/application-javascript/package.json @@ -9,8 +9,14 @@ "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", + "scripts": { + "lint": "eslint *.js" + }, "dependencies": { "fabric-ca-client": "^2.2.4", "fabric-network": "^2.2.4" + }, + "devDependencies": { + "eslint": "^7.32.0" } } diff --git a/auction-dutch/application-javascript/package.json b/auction-dutch/application-javascript/package.json index cd0ea6f9..7966b24c 100644 --- a/auction-dutch/application-javascript/package.json +++ b/auction-dutch/application-javascript/package.json @@ -9,6 +9,10 @@ "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", + "scripts": { + "lint": "eslint *.js" + + }, "dependencies": { "fabric-ca-client": "^2.2.4", "fabric-network": "^2.2.4" diff --git a/auction-simple/application-javascript/package.json b/auction-simple/application-javascript/package.json index 4a410a62..d4367db0 100644 --- a/auction-simple/application-javascript/package.json +++ b/auction-simple/application-javascript/package.json @@ -9,8 +9,14 @@ "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", + "scripts": { + "lint": "eslint *.js" + }, "dependencies": { "fabric-ca-client": "^2.2.4", "fabric-network": "^2.2.4" + }, + "devDependencies": { + "eslint": "^7.32.0" } } diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 2b8a0a27..051eccfc 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -85,8 +85,6 @@ jobs: inputs: versionSpec: $(NODE_VER) displayName: Install Node.js - - script: npm install -g typescript eslint tslint - displayName: Install Javascript Linting Deps - script: ./ci/scripts/lint.sh displayName: Lint Code diff --git a/ci/scripts/lint.sh b/ci/scripts/lint.sh index 55be08e4..131799ba 100755 --- a/ci/scripts/lint.sh +++ b/ci/scripts/lint.sh @@ -29,13 +29,11 @@ for dir in $dirs; do print "The following files contain import errors, please run 'goimports -l -w ' to fix these issues:" echo "${output}" fi - elif [[ "$dir" =~ "-javascript" ]]; then - print "Running ESLint" - if [[ "$dir" =~ "chaincode" ]]; then - eslint *.js */**.js - else - eslint *.js - fi + elif [[ "$dir" =~ "-javascript" || "$dir" =~ "-typescript" ]]; then + print "Installing node modules" + npm install + print "Running Lint" + npm run lint elif [[ "$dir" =~ "-java" ]]; then if [[ -f "pom.xml" ]]; then print "Running Maven Build" @@ -44,9 +42,6 @@ for dir in $dirs; do print "Running Gradle Build" ./gradlew build fi - elif [[ "$dir" =~ "-typescript" ]]; then - print "Running TSLint" - tslint --project . fi popd fi From 216d422f112b16d59fcd9b265ff58ffb794ab1ad Mon Sep 17 00:00:00 2001 From: nao Date: Wed, 6 Oct 2021 21:34:04 +0900 Subject: [PATCH 010/106] Fix: Cannot launch chaincode in nano bash in Linux (#468) CHAINCODEADDRESS is set to host.docker.internal which is only available in MAC and Windows environments. For that reason, it cannot launch chaincode on Linux. This PR sets CHAINCODEADDRESS to 127.0.0.1 instead of host.docker.internal. Signed-off-by: Nao Nishijima --- test-network-nano-bash/peer1.sh | 8 +++++++- test-network-nano-bash/peer2.sh | 8 +++++++- test-network-nano-bash/peer3.sh | 8 +++++++- test-network-nano-bash/peer4.sh | 8 +++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/test-network-nano-bash/peer1.sh b/test-network-nano-bash/peer1.sh index 6655936b..89d5d8da 100755 --- a/test-network-nano-bash/peer1.sh +++ b/test-network-nano-bash/peer1.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash set -euo pipefail +if [ "$(uname)" == "Linux" ] ; then + CCADDR="127.0.0.1" +else + CCADDR="host.docker.internal" +fi + # look for binaries in local dev environment /build/bin directory and then in local samples /bin directory export PATH="${PWD}"/../../fabric/build/bin:"${PWD}"/../bin:"$PATH" export FABRIC_CFG_PATH="${PWD}"/../config @@ -13,7 +19,7 @@ export CORE_PEER_TLS_ROOTCERT_FILE="${PWD}"/crypto-config/peerOrganizations/org1 export CORE_PEER_ID=peer0.org1.example.com export CORE_PEER_ADDRESS=127.0.0.1:7051 export CORE_PEER_LISTENADDRESS=127.0.0.1:7051 -export CORE_PEER_CHAINCODEADDRESS=host.docker.internal:7052 +export CORE_PEER_CHAINCODEADDRESS="${CCADDR}":7052 export CORE_PEER_CHAINCODELISTENADDRESS=127.0.0.1:7052 # bootstrap peer is the other peer in the same org export CORE_PEER_GOSSIP_BOOTSTRAP=127.0.0.1:7053 diff --git a/test-network-nano-bash/peer2.sh b/test-network-nano-bash/peer2.sh index 39f66312..163df06e 100755 --- a/test-network-nano-bash/peer2.sh +++ b/test-network-nano-bash/peer2.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash set -euo pipefail +if [ "$(uname)" == "Linux" ] ; then + CCADDR="127.0.0.1" +else + CCADDR="host.docker.internal" +fi + # look for binaries in local dev environment /build/bin directory and then in local samples /bin directory export PATH="${PWD}"/../../fabric/build/bin:"${PWD}"/../bin:"$PATH" export FABRIC_CFG_PATH="${PWD}"/../config @@ -13,7 +19,7 @@ export CORE_PEER_TLS_ROOTCERT_FILE="${PWD}"/crypto-config/peerOrganizations/org1 export CORE_PEER_ID=peer1.org1.example.com export CORE_PEER_ADDRESS=127.0.0.1:7053 export CORE_PEER_LISTENADDRESS=127.0.0.1:7053 -export CORE_PEER_CHAINCODEADDRESS=host.docker.internal:7054 +export CORE_PEER_CHAINCODEADDRESS="${CCADDR}":7054 export CORE_PEER_CHAINCODELISTENADDRESS=127.0.0.1:7054 # bootstrap peer is the other peer in the same org export CORE_PEER_GOSSIP_BOOTSTRAP=127.0.0.1:7051 diff --git a/test-network-nano-bash/peer3.sh b/test-network-nano-bash/peer3.sh index 58abfdf0..1054118f 100755 --- a/test-network-nano-bash/peer3.sh +++ b/test-network-nano-bash/peer3.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash set -euo pipefail +if [ "$(uname)" == "Linux" ] ; then + CCADDR="127.0.0.1" +else + CCADDR="host.docker.internal" +fi + # look for binaries in local dev environment /build/bin directory and then in local samples /bin directory export PATH="${PWD}"/../../fabric/build/bin:"${PWD}"/../bin:"$PATH" export FABRIC_CFG_PATH="${PWD}"/../config @@ -13,7 +19,7 @@ export CORE_PEER_TLS_ROOTCERT_FILE="${PWD}"/crypto-config/peerOrganizations/org2 export CORE_PEER_ID=peer0.org2.example.com export CORE_PEER_ADDRESS=127.0.0.1:7055 export CORE_PEER_LISTENADDRESS=127.0.0.1:7055 -export CORE_PEER_CHAINCODEADDRESS=host.docker.internal:7056 +export CORE_PEER_CHAINCODEADDRESS="${CCADDR}":7056 export CORE_PEER_CHAINCODELISTENADDRESS=127.0.0.1:7056 # bootstrap peer is the other peer in the same org export CORE_PEER_GOSSIP_BOOTSTRAP=127.0.0.1:7057 diff --git a/test-network-nano-bash/peer4.sh b/test-network-nano-bash/peer4.sh index 2923f874..a62afe58 100755 --- a/test-network-nano-bash/peer4.sh +++ b/test-network-nano-bash/peer4.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash set -euo pipefail +if [ "$(uname)" == "Linux" ] ; then + CCADDR="127.0.0.1" +else + CCADDR="host.docker.internal" +fi + # look for binaries in local dev environment /build/bin directory and then in local samples /bin directory export PATH="${PWD}"/../../fabric/build/bin:"${PWD}"/../bin:"$PATH" export FABRIC_CFG_PATH="${PWD}"/../config @@ -13,7 +19,7 @@ export CORE_PEER_TLS_ROOTCERT_FILE="${PWD}"/crypto-config/peerOrganizations/org2 export CORE_PEER_ID=peer0.org2.example.com export CORE_PEER_ADDRESS=127.0.0.1:7057 export CORE_PEER_LISTENADDRESS=127.0.0.1:7057 -export CORE_PEER_CHAINCODEADDRESS=host.docker.internal:7058 +export CORE_PEER_CHAINCODEADDRESS="${CCADDR}":7058 export CORE_PEER_CHAINCODELISTENADDRESS=127.0.0.1:7058 # bootstrap peer is the other peer in the same org export CORE_PEER_GOSSIP_BOOTSTRAP=127.0.0.1:7055 From 3ba63b15d6c3f1f469560f31125c95abad594d6b Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Wed, 6 Oct 2021 16:35:43 +0100 Subject: [PATCH 011/106] Update go.mod (#500) Signed-off-by: Matthew B White --- asset-transfer-abac/chaincode-go/go.mod | 4 +--- asset-transfer-abac/chaincode-go/go.sum | 10 ++++++++++ asset-transfer-basic/application-go/go.mod | 4 +--- asset-transfer-basic/application-go/go.sum | 10 ++++++++++ asset-transfer-basic/chaincode-go/go.mod | 4 +--- asset-transfer-basic/chaincode-go/go.sum | 10 ++++++++++ asset-transfer-ledger-queries/chaincode-go/go.mod | 4 +--- asset-transfer-ledger-queries/chaincode-go/go.sum | 10 ++++++++++ asset-transfer-private-data/chaincode-go/go.mod | 4 +--- asset-transfer-private-data/chaincode-go/go.sum | 10 ++++++++++ asset-transfer-secured-agreement/chaincode-go/go.mod | 4 +--- asset-transfer-secured-agreement/chaincode-go/go.sum | 10 ++++++++++ auction-dutch/chaincode-go/go.mod | 4 +--- auction-dutch/chaincode-go/go.sum | 10 ++++++++++ auction-simple/chaincode-go/go.mod | 4 +--- auction-simple/chaincode-go/go.sum | 10 ++++++++++ ci/scripts/lint.sh | 3 ++- .../organization/digibank/contract-go/go.mod | 4 +--- .../organization/digibank/contract-go/go.sum | 10 ++++++++++ .../organization/magnetocorp/contract-go/go.mod | 4 +--- .../organization/magnetocorp/contract-go/go.sum | 10 ++++++++++ high-throughput/application-go/go.mod | 4 +--- high-throughput/application-go/go.sum | 10 ++++++++++ high-throughput/chaincode-go/go.mod | 4 +--- high-throughput/chaincode-go/go.sum | 10 ++++++++++ token-erc-1155/chaincode-go/go.mod | 4 +--- token-erc-1155/chaincode-go/go.sum | 10 ++++++++++ token-erc-20/chaincode-go/go.mod | 4 +--- token-erc-20/chaincode-go/go.sum | 10 ++++++++++ token-utxo/chaincode-go/go.mod | 4 +--- token-utxo/chaincode-go/go.sum | 10 ++++++++++ 31 files changed, 167 insertions(+), 46 deletions(-) diff --git a/asset-transfer-abac/chaincode-go/go.mod b/asset-transfer-abac/chaincode-go/go.mod index 6730b91d..4827829f 100644 --- a/asset-transfer-abac/chaincode-go/go.mod +++ b/asset-transfer-abac/chaincode-go/go.mod @@ -4,7 +4,5 @@ go 1.15 require ( github.com/hyperledger/fabric-contract-api-go v1.1.1 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect ) diff --git a/asset-transfer-abac/chaincode-go/go.sum b/asset-transfer-abac/chaincode-go/go.sum index 0884bc65..81e30b4a 100644 --- a/asset-transfer-abac/chaincode-go/go.sum +++ b/asset-transfer-abac/chaincode-go/go.sum @@ -100,6 +100,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -116,6 +117,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -128,13 +131,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -143,6 +151,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-basic/application-go/go.mod b/asset-transfer-basic/application-go/go.mod index d7c5f637..0db68899 100644 --- a/asset-transfer-basic/application-go/go.mod +++ b/asset-transfer-basic/application-go/go.mod @@ -5,8 +5,6 @@ go 1.14 require ( github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/asset-transfer-basic/application-go/go.sum b/asset-transfer-basic/application-go/go.sum index 9d189073..64e35e00 100644 --- a/asset-transfer-basic/application-go/go.sum +++ b/asset-transfer-basic/application-go/go.sum @@ -158,6 +158,7 @@ github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -191,6 +192,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -206,14 +209,19 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -223,6 +231,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-basic/chaincode-go/go.mod b/asset-transfer-basic/chaincode-go/go.mod index 31ab687b..7a306490 100644 --- a/asset-transfer-basic/chaincode-go/go.mod +++ b/asset-transfer-basic/chaincode-go/go.mod @@ -8,7 +8,5 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e github.com/stretchr/testify v1.5.1 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect ) diff --git a/asset-transfer-basic/chaincode-go/go.sum b/asset-transfer-basic/chaincode-go/go.sum index 8b6fa693..4a64c265 100644 --- a/asset-transfer-basic/chaincode-go/go.sum +++ b/asset-transfer-basic/chaincode-go/go.sum @@ -100,6 +100,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -116,6 +117,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -128,13 +131,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -143,6 +151,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-ledger-queries/chaincode-go/go.mod b/asset-transfer-ledger-queries/chaincode-go/go.mod index e060e458..7f6d5c34 100644 --- a/asset-transfer-ledger-queries/chaincode-go/go.mod +++ b/asset-transfer-ledger-queries/chaincode-go/go.mod @@ -6,7 +6,5 @@ require ( github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect ) diff --git a/asset-transfer-ledger-queries/chaincode-go/go.sum b/asset-transfer-ledger-queries/chaincode-go/go.sum index 9bbd040e..488f925a 100644 --- a/asset-transfer-ledger-queries/chaincode-go/go.sum +++ b/asset-transfer-ledger-queries/chaincode-go/go.sum @@ -101,6 +101,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -117,6 +118,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -129,13 +132,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -144,6 +152,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-private-data/chaincode-go/go.mod b/asset-transfer-private-data/chaincode-go/go.mod index 31f32b5e..24bf449c 100644 --- a/asset-transfer-private-data/chaincode-go/go.mod +++ b/asset-transfer-private-data/chaincode-go/go.mod @@ -16,9 +16,7 @@ require ( github.com/rogpeppe/go-internal v1.6.0 // indirect github.com/stretchr/testify v1.5.1 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986 // indirect google.golang.org/grpc v1.30.0 // indirect diff --git a/asset-transfer-private-data/chaincode-go/go.sum b/asset-transfer-private-data/chaincode-go/go.sum index 35e65707..0bf7e8ad 100644 --- a/asset-transfer-private-data/chaincode-go/go.sum +++ b/asset-transfer-private-data/chaincode-go/go.sum @@ -130,6 +130,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -152,6 +153,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -167,13 +170,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -184,6 +192,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/asset-transfer-secured-agreement/chaincode-go/go.mod b/asset-transfer-secured-agreement/chaincode-go/go.mod index 4662158f..e9cfa7e0 100644 --- a/asset-transfer-secured-agreement/chaincode-go/go.mod +++ b/asset-transfer-secured-agreement/chaincode-go/go.mod @@ -6,7 +6,5 @@ require ( github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-chaincode-go v0.0.0-20200128192331-2d899240a7ed github.com/hyperledger/fabric-contract-api-go v1.0.0 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect ) diff --git a/asset-transfer-secured-agreement/chaincode-go/go.sum b/asset-transfer-secured-agreement/chaincode-go/go.sum index b8bb8d34..685cf666 100644 --- a/asset-transfer-secured-agreement/chaincode-go/go.sum +++ b/asset-transfer-secured-agreement/chaincode-go/go.sum @@ -99,6 +99,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -115,6 +116,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -127,13 +130,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -143,6 +151,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/auction-dutch/chaincode-go/go.mod b/auction-dutch/chaincode-go/go.mod index 0eb59b96..e679aba1 100644 --- a/auction-dutch/chaincode-go/go.mod +++ b/auction-dutch/chaincode-go/go.mod @@ -7,8 +7,6 @@ require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20201119163726-f8ef75b17719 github.com/hyperledger/fabric-contract-api-go v1.1.1 github.com/hyperledger/fabric-protos-go v0.0.0-20210127161553-4f432a78f286 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/auction-dutch/chaincode-go/go.sum b/auction-dutch/chaincode-go/go.sum index 8b1f4390..0171140d 100644 --- a/auction-dutch/chaincode-go/go.sum +++ b/auction-dutch/chaincode-go/go.sum @@ -112,6 +112,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -128,6 +129,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -140,13 +143,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -155,6 +163,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/auction-simple/chaincode-go/go.mod b/auction-simple/chaincode-go/go.mod index ba8272cf..934863e6 100644 --- a/auction-simple/chaincode-go/go.mod +++ b/auction-simple/chaincode-go/go.mod @@ -5,7 +5,5 @@ go 1.15 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20200728190242-9b3ae92d8664 github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect ) diff --git a/auction-simple/chaincode-go/go.sum b/auction-simple/chaincode-go/go.sum index 4e88963d..949f6c87 100644 --- a/auction-simple/chaincode-go/go.sum +++ b/auction-simple/chaincode-go/go.sum @@ -101,6 +101,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -117,6 +118,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -129,13 +132,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -144,6 +152,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/ci/scripts/lint.sh b/ci/scripts/lint.sh index 131799ba..89312345 100755 --- a/ci/scripts/lint.sh +++ b/ci/scripts/lint.sh @@ -1,3 +1,4 @@ +#!/bin/bash set -euo pipefail function print() { @@ -9,7 +10,7 @@ function print() { dirs=("$(find . -name "*-go" -o -name "*-java" -o -name "*-javascript" -o -name "*-typescript")") for dir in $dirs; do - if [[ -d $dir ]]; then + if [[ -d $dir ]] && [[ ! $dir =~ node_modules ]]; then print "Linting $dir" pushd $dir if [[ "$dir" =~ "-go" ]]; then diff --git a/commercial-paper/organization/digibank/contract-go/go.mod b/commercial-paper/organization/digibank/contract-go/go.mod index 3c2ae75e..534664a1 100644 --- a/commercial-paper/organization/digibank/contract-go/go.mod +++ b/commercial-paper/organization/digibank/contract-go/go.mod @@ -7,9 +7,7 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/mailru/easyjson v0.7.0 // indirect github.com/stretchr/testify v1.5.1 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect google.golang.org/grpc v1.24.0 // indirect ) diff --git a/commercial-paper/organization/digibank/contract-go/go.sum b/commercial-paper/organization/digibank/contract-go/go.sum index 5d3d13ee..d84263c8 100644 --- a/commercial-paper/organization/digibank/contract-go/go.sum +++ b/commercial-paper/organization/digibank/contract-go/go.sum @@ -103,6 +103,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -125,6 +126,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -140,13 +143,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -157,6 +165,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/commercial-paper/organization/magnetocorp/contract-go/go.mod b/commercial-paper/organization/magnetocorp/contract-go/go.mod index 147604fd..c81701b9 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/go.mod +++ b/commercial-paper/organization/magnetocorp/contract-go/go.mod @@ -7,9 +7,7 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/mailru/easyjson v0.7.0 // indirect github.com/stretchr/testify v1.5.1 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect google.golang.org/grpc v1.24.0 // indirect ) diff --git a/commercial-paper/organization/magnetocorp/contract-go/go.sum b/commercial-paper/organization/magnetocorp/contract-go/go.sum index 5d3d13ee..d84263c8 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/go.sum +++ b/commercial-paper/organization/magnetocorp/contract-go/go.sum @@ -103,6 +103,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -125,6 +126,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -140,13 +143,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -157,6 +165,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/high-throughput/application-go/go.mod b/high-throughput/application-go/go.mod index 36fd191c..0529e002 100644 --- a/high-throughput/application-go/go.mod +++ b/high-throughput/application-go/go.mod @@ -5,8 +5,6 @@ go 1.14 require ( github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/high-throughput/application-go/go.sum b/high-throughput/application-go/go.sum index 9d189073..64e35e00 100644 --- a/high-throughput/application-go/go.sum +++ b/high-throughput/application-go/go.sum @@ -158,6 +158,7 @@ github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -191,6 +192,8 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -206,14 +209,19 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -223,6 +231,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/high-throughput/chaincode-go/go.mod b/high-throughput/chaincode-go/go.mod index dd5fccdd..d8e7e674 100644 --- a/high-throughput/chaincode-go/go.mod +++ b/high-throughput/chaincode-go/go.mod @@ -5,8 +5,6 @@ go 1.12 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect ) diff --git a/high-throughput/chaincode-go/go.sum b/high-throughput/chaincode-go/go.sum index 2e2fa959..73459fee 100644 --- a/high-throughput/chaincode-go/go.sum +++ b/high-throughput/chaincode-go/go.sum @@ -30,6 +30,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -47,6 +48,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -58,12 +61,17 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -73,6 +81,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/token-erc-1155/chaincode-go/go.mod b/token-erc-1155/chaincode-go/go.mod index c78f40ae..98331bbe 100644 --- a/token-erc-1155/chaincode-go/go.mod +++ b/token-erc-1155/chaincode-go/go.mod @@ -4,7 +4,5 @@ go 1.16 require ( github.com/hyperledger/fabric-contract-api-go v1.1.1 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect ) diff --git a/token-erc-1155/chaincode-go/go.sum b/token-erc-1155/chaincode-go/go.sum index 0884bc65..81e30b4a 100644 --- a/token-erc-1155/chaincode-go/go.sum +++ b/token-erc-1155/chaincode-go/go.sum @@ -100,6 +100,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -116,6 +117,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -128,13 +131,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -143,6 +151,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/token-erc-20/chaincode-go/go.mod b/token-erc-20/chaincode-go/go.mod index c29e7850..2d8fd89d 100644 --- a/token-erc-20/chaincode-go/go.mod +++ b/token-erc-20/chaincode-go/go.mod @@ -4,7 +4,5 @@ go 1.14 require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect ) diff --git a/token-erc-20/chaincode-go/go.sum b/token-erc-20/chaincode-go/go.sum index 8b6fa693..4a64c265 100644 --- a/token-erc-20/chaincode-go/go.sum +++ b/token-erc-20/chaincode-go/go.sum @@ -100,6 +100,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -116,6 +117,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -128,13 +131,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -143,6 +151,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/token-utxo/chaincode-go/go.mod b/token-utxo/chaincode-go/go.mod index 0674345b..03f30d88 100644 --- a/token-utxo/chaincode-go/go.mod +++ b/token-utxo/chaincode-go/go.mod @@ -4,7 +4,5 @@ go 1.14 require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.5 // indirect + golang.org/x/tools v0.1.7 // indirect ) diff --git a/token-utxo/chaincode-go/go.sum b/token-utxo/chaincode-go/go.sum index 8b6fa693..4a64c265 100644 --- a/token-utxo/chaincode-go/go.sum +++ b/token-utxo/chaincode-go/go.sum @@ -100,6 +100,7 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -116,6 +117,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -128,13 +131,18 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -143,6 +151,8 @@ golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= From 30fb81a34178d17cb4bf1f5a11148d97d9118b84 Mon Sep 17 00:00:00 2001 From: jkneubuh <86427252+jkneubuh@users.noreply.github.com> Date: Wed, 6 Oct 2021 11:50:39 -0400 Subject: [PATCH 012/106] Run the fabric test network on Kubernetes (#498) * Run the fabric test network on Kubernetes Signed-off-by: Josh Kneubuhl * Re-LINT Signed-off-by: Josh Kneubuhl --- test-network-k8s/.gitignore | 5 + test-network-k8s/README.md | 78 ++ .../connection.json | 5 + .../asset-transfer-basic-debug/metadata.json | 4 + .../asset-transfer-basic/connection.json | 5 + .../asset-transfer-basic/metadata.json | 4 + test-network-k8s/config/org0/configtx.yaml | 415 ++++++++++ .../org0/fabric-ecert-ca-server-config.yaml | 506 ++++++++++++ .../org0/fabric-tls-ca-server-config.yaml | 496 ++++++++++++ test-network-k8s/config/org0/orderer.yaml | 420 ++++++++++ test-network-k8s/config/org1/core.yaml | 759 ++++++++++++++++++ .../org1/fabric-ecert-ca-server-config.yaml | 506 ++++++++++++ .../org1/fabric-tls-ca-server-config.yaml | 496 ++++++++++++ test-network-k8s/config/org2/core.yaml | 759 ++++++++++++++++++ .../org2/fabric-ecert-ca-server-config.yaml | 506 ++++++++++++ .../org2/fabric-tls-ca-server-config.yaml | 496 ++++++++++++ test-network-k8s/docs/APPLICATIONS.md | 106 +++ test-network-k8s/docs/CA.md | 281 +++++++ test-network-k8s/docs/CHAINCODE.md | 278 +++++++ test-network-k8s/docs/CHANNELS.md | 206 +++++ test-network-k8s/docs/KUBERNETES.md | 161 ++++ test-network-k8s/docs/README.md | 49 ++ test-network-k8s/docs/TEST_NETWORK.md | 221 +++++ test-network-k8s/docs/images/test-network.png | Bin 0 -> 225031 bytes .../kube/application-deployment.yaml | 48 ++ test-network-k8s/kube/fabric-rest-sample.yaml | 258 ++++++ test-network-k8s/kube/ingress-nginx.yaml | 687 ++++++++++++++++ .../kube/job-scrub-fabric-volumes.yaml | 43 + test-network-k8s/kube/ns-test-network.yaml | 10 + .../kube/org0/org0-admin-cli.yaml | 61 ++ test-network-k8s/kube/org0/org0-ecert-ca.yaml | 69 ++ test-network-k8s/kube/org0/org0-orderer1.yaml | 85 ++ test-network-k8s/kube/org0/org0-orderer2.yaml | 85 ++ test-network-k8s/kube/org0/org0-orderer3.yaml | 85 ++ test-network-k8s/kube/org0/org0-tls-ca.yaml | 65 ++ .../kube/org1/org1-admin-cli.yaml | 65 ++ .../kube/org1/org1-cc-template.yaml | 45 ++ test-network-k8s/kube/org1/org1-ecert-ca.yaml | 69 ++ test-network-k8s/kube/org1/org1-peer1.yaml | 103 +++ test-network-k8s/kube/org1/org1-peer2.yaml | 89 ++ test-network-k8s/kube/org1/org1-tls-ca.yaml | 65 ++ .../kube/org2/org2-admin-cli.yaml | 65 ++ test-network-k8s/kube/org2/org2-cc.yaml | 6 + test-network-k8s/kube/org2/org2-ecert-ca.yaml | 69 ++ test-network-k8s/kube/org2/org2-peer1.yaml | 104 +++ test-network-k8s/kube/org2/org2-peer2.yaml | 89 ++ test-network-k8s/kube/org2/org2-tls-ca.yaml | 65 ++ test-network-k8s/kube/pv-fabric-org0.yaml | 18 + test-network-k8s/kube/pv-fabric-org1.yaml | 18 + test-network-k8s/kube/pv-fabric-org2.yaml | 18 + test-network-k8s/kube/pvc-fabric-org0.yaml | 17 + test-network-k8s/kube/pvc-fabric-org1.yaml | 17 + test-network-k8s/kube/pvc-fabric-org2.yaml | 17 + test-network-k8s/network | 157 ++++ .../scripts/application_connection.sh | 114 +++ test-network-k8s/scripts/appuser.id.template | 9 + test-network-k8s/scripts/ccp-template.json | 49 ++ test-network-k8s/scripts/chaincode.sh | 172 ++++ test-network-k8s/scripts/channel.sh | 201 +++++ test-network-k8s/scripts/fabric_CAs.sh | 137 ++++ test-network-k8s/scripts/fabric_config.sh | 42 + test-network-k8s/scripts/kind.sh | 134 ++++ test-network-k8s/scripts/prereqs.sh | 28 + test-network-k8s/scripts/rest_sample.sh | 91 +++ test-network-k8s/scripts/set_anchor_peer.sh | 110 +++ test-network-k8s/scripts/test_network.sh | 259 ++++++ test-network-k8s/scripts/utils.sh | 66 ++ 67 files changed, 10766 insertions(+) create mode 100644 test-network-k8s/.gitignore create mode 100644 test-network-k8s/README.md create mode 100644 test-network-k8s/chaincode/asset-transfer-basic-debug/connection.json create mode 100644 test-network-k8s/chaincode/asset-transfer-basic-debug/metadata.json create mode 100644 test-network-k8s/chaincode/asset-transfer-basic/connection.json create mode 100644 test-network-k8s/chaincode/asset-transfer-basic/metadata.json create mode 100644 test-network-k8s/config/org0/configtx.yaml create mode 100644 test-network-k8s/config/org0/fabric-ecert-ca-server-config.yaml create mode 100644 test-network-k8s/config/org0/fabric-tls-ca-server-config.yaml create mode 100644 test-network-k8s/config/org0/orderer.yaml create mode 100644 test-network-k8s/config/org1/core.yaml create mode 100644 test-network-k8s/config/org1/fabric-ecert-ca-server-config.yaml create mode 100644 test-network-k8s/config/org1/fabric-tls-ca-server-config.yaml create mode 100644 test-network-k8s/config/org2/core.yaml create mode 100644 test-network-k8s/config/org2/fabric-ecert-ca-server-config.yaml create mode 100644 test-network-k8s/config/org2/fabric-tls-ca-server-config.yaml create mode 100644 test-network-k8s/docs/APPLICATIONS.md create mode 100644 test-network-k8s/docs/CA.md create mode 100644 test-network-k8s/docs/CHAINCODE.md create mode 100644 test-network-k8s/docs/CHANNELS.md create mode 100644 test-network-k8s/docs/KUBERNETES.md create mode 100644 test-network-k8s/docs/README.md create mode 100644 test-network-k8s/docs/TEST_NETWORK.md create mode 100644 test-network-k8s/docs/images/test-network.png create mode 100644 test-network-k8s/kube/application-deployment.yaml create mode 100644 test-network-k8s/kube/fabric-rest-sample.yaml create mode 100644 test-network-k8s/kube/ingress-nginx.yaml create mode 100644 test-network-k8s/kube/job-scrub-fabric-volumes.yaml create mode 100644 test-network-k8s/kube/ns-test-network.yaml create mode 100644 test-network-k8s/kube/org0/org0-admin-cli.yaml create mode 100644 test-network-k8s/kube/org0/org0-ecert-ca.yaml create mode 100644 test-network-k8s/kube/org0/org0-orderer1.yaml create mode 100644 test-network-k8s/kube/org0/org0-orderer2.yaml create mode 100644 test-network-k8s/kube/org0/org0-orderer3.yaml create mode 100644 test-network-k8s/kube/org0/org0-tls-ca.yaml create mode 100644 test-network-k8s/kube/org1/org1-admin-cli.yaml create mode 100644 test-network-k8s/kube/org1/org1-cc-template.yaml create mode 100644 test-network-k8s/kube/org1/org1-ecert-ca.yaml create mode 100644 test-network-k8s/kube/org1/org1-peer1.yaml create mode 100644 test-network-k8s/kube/org1/org1-peer2.yaml create mode 100644 test-network-k8s/kube/org1/org1-tls-ca.yaml create mode 100644 test-network-k8s/kube/org2/org2-admin-cli.yaml create mode 100644 test-network-k8s/kube/org2/org2-cc.yaml create mode 100644 test-network-k8s/kube/org2/org2-ecert-ca.yaml create mode 100644 test-network-k8s/kube/org2/org2-peer1.yaml create mode 100644 test-network-k8s/kube/org2/org2-peer2.yaml create mode 100644 test-network-k8s/kube/org2/org2-tls-ca.yaml create mode 100644 test-network-k8s/kube/pv-fabric-org0.yaml create mode 100644 test-network-k8s/kube/pv-fabric-org1.yaml create mode 100644 test-network-k8s/kube/pv-fabric-org2.yaml create mode 100644 test-network-k8s/kube/pvc-fabric-org0.yaml create mode 100644 test-network-k8s/kube/pvc-fabric-org1.yaml create mode 100644 test-network-k8s/kube/pvc-fabric-org2.yaml create mode 100755 test-network-k8s/network create mode 100755 test-network-k8s/scripts/application_connection.sh create mode 100644 test-network-k8s/scripts/appuser.id.template create mode 100755 test-network-k8s/scripts/ccp-template.json create mode 100755 test-network-k8s/scripts/chaincode.sh create mode 100755 test-network-k8s/scripts/channel.sh create mode 100755 test-network-k8s/scripts/fabric_CAs.sh create mode 100755 test-network-k8s/scripts/fabric_config.sh create mode 100755 test-network-k8s/scripts/kind.sh create mode 100755 test-network-k8s/scripts/prereqs.sh create mode 100755 test-network-k8s/scripts/rest_sample.sh create mode 100755 test-network-k8s/scripts/set_anchor_peer.sh create mode 100755 test-network-k8s/scripts/test_network.sh create mode 100644 test-network-k8s/scripts/utils.sh diff --git a/test-network-k8s/.gitignore b/test-network-k8s/.gitignore new file mode 100644 index 00000000..b4afee58 --- /dev/null +++ b/test-network-k8s/.gitignore @@ -0,0 +1,5 @@ +.idea/ +network.log +network-debug.log +build/ +.env diff --git a/test-network-k8s/README.md b/test-network-k8s/README.md new file mode 100644 index 00000000..577c0394 --- /dev/null +++ b/test-network-k8s/README.md @@ -0,0 +1,78 @@ +# Kubernetes Test Network + +This project re-establishes the Hyperledger [test-network](../test-network) as a _cloud native_ application. + +### Objectives: + +- Provide a simple, _one click_ activity for running the Fabric test network. +- Provide a reference guide for deploying _production-style_ networks on Kubernetes. +- Provide a _cloud ready_ platform for developing chaincode, Gateway, and blockchain apps. +- Provide a Kube supplement to the Fabric [CA Operations and Deployment](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/ca-deploy.html) guides. +- Support a transition to [Chaincode as a Service](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html). +- Support a transition from the Internal, Docker daemon to [External Chaincode](https://hyperledger-fabric.readthedocs.io/en/latest/cc_launcher.html) builders. +- Run on any Kube. + +_Fabric, Ahoy!_ + + +## Prerequisites + +- [Docker](https://www.docker.com) +- [kubectl](https://kubernetes.io/docs/tasks/tools/) +- [kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) + + +## Quickstart + +Create a local Kubernetes cluster: +```shell +./network kind +``` + +Launch the network, create a channel, and deploy the [basic-asset-transfer](../asset-transfer-basic) smart contract: +```shell +./network up +./network channel create +./network chaincode deploy +``` + +Invoke and query chaincode: +```shell +./network chaincode invoke '{"Args":["CreateAsset","1","blue","35","tom","1000"]}' +./network chaincode query '{"Args":["ReadAsset","1"]}' +``` + +Access the blockchain with a [REST API](https://github.com/hyperledgendary/fabric-rest-sample/tree/main/asset-transfer-basic/rest-api-typescript#rest-api): +``` +./network rest-easy +``` + +Tear down the test network: +```shell +./network down +``` + +Tear down the cluster: +```shell +./network unkind +``` + + +## [Detailed Guides](docs/README.md) + +- [`./network`](docs/NETWORK.md) +- [Working with Kubernetes](docs/KUBERNETES.md) +- [Certificate Authorities](docs/CA.md) +- [Launching the Test Network](docs/TEST_NETWORK.md) +- [Working with Channels](docs/CHANNELS.md) +- [Working with Chaincode](docs/CHAINCODE.md) +- [Working with Applications](docs/APPLICATIONS.md) + + +## Areas for Improvement / TODOs + +- [ ] Test the recipe with OCP, AWS, gcp, Azure, etc. (These should ONLY differ w.r.t. pvc and ingress) +- [ ] Implement @celder mechanism for bootstrapping dual-headed CAs w/o poisoning the root CA on expiry. +- [ ] Address any of the 20+ todo: notes in network.sh +- [ ] Implement mutual TLS across peers, orderers, and clients. +- [ ] Caliper? diff --git a/test-network-k8s/chaincode/asset-transfer-basic-debug/connection.json b/test-network-k8s/chaincode/asset-transfer-basic-debug/connection.json new file mode 100644 index 00000000..030c8ee1 --- /dev/null +++ b/test-network-k8s/chaincode/asset-transfer-basic-debug/connection.json @@ -0,0 +1,5 @@ +{ + "address": "host.docker.internal:9999", + "dial_timeout": "10s", + "tls_required": false +} diff --git a/test-network-k8s/chaincode/asset-transfer-basic-debug/metadata.json b/test-network-k8s/chaincode/asset-transfer-basic-debug/metadata.json new file mode 100644 index 00000000..bb7056c0 --- /dev/null +++ b/test-network-k8s/chaincode/asset-transfer-basic-debug/metadata.json @@ -0,0 +1,4 @@ +{ + "type": "external", + "label": "basic_1.0" +} \ No newline at end of file diff --git a/test-network-k8s/chaincode/asset-transfer-basic/connection.json b/test-network-k8s/chaincode/asset-transfer-basic/connection.json new file mode 100644 index 00000000..598ba74f --- /dev/null +++ b/test-network-k8s/chaincode/asset-transfer-basic/connection.json @@ -0,0 +1,5 @@ +{ + "address": "org1-cc-asset-transfer-basic:9999", + "dial_timeout": "10s", + "tls_required": false +} \ No newline at end of file diff --git a/test-network-k8s/chaincode/asset-transfer-basic/metadata.json b/test-network-k8s/chaincode/asset-transfer-basic/metadata.json new file mode 100644 index 00000000..bb7056c0 --- /dev/null +++ b/test-network-k8s/chaincode/asset-transfer-basic/metadata.json @@ -0,0 +1,4 @@ +{ + "type": "external", + "label": "basic_1.0" +} \ No newline at end of file diff --git a/test-network-k8s/config/org0/configtx.yaml b/test-network-k8s/config/org0/configtx.yaml new file mode 100644 index 00000000..337c83c2 --- /dev/null +++ b/test-network-k8s/config/org0/configtx.yaml @@ -0,0 +1,415 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +--- +################################################################################ +# +# Section: Organizations +# +# - This section defines the different organizational identities which will +# be referenced later in the configuration. +# +################################################################################ +Organizations: + + # SampleOrg defines an MSP using the sampleconfig. It should never be used + # in production but may be used as a template for other definitions + - &OrdererOrg + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: OrdererOrg + + # ID to load the MSP definition as + ID: OrdererMSP + + # MSPDir is the filesystem path which contains the MSP configuration + MSPDir: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('OrdererMSP.member')" + Writers: + Type: Signature + Rule: "OR('OrdererMSP.member')" + Admins: + Type: Signature + Rule: "OR('OrdererMSP.admin')" + + OrdererEndpoints: + - org0-orderer1:6050 + - org0-orderer2:6050 + - org0-orderer3:6050 + + - &Org1 + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: Org1MSP + + # ID to load the MSP definition as + ID: Org1MSP + + MSPDir: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')" + Writers: + Type: Signature + Rule: "OR('Org1MSP.admin', 'Org1MSP.client')" + Admins: + Type: Signature + Rule: "OR('Org1MSP.admin')" + Endorsement: + Type: Signature + Rule: "OR('Org1MSP.peer')" + + # leave this flag set to true. + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: org1-peer1 + Port: 7051 + + - &Org2 + # DefaultOrg defines the organization which is used in the sampleconfig + # of the fabric.git development environment + Name: Org2MSP + + # ID to load the MSP definition as + ID: Org2MSP + + MSPDir: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/msp + + # Policies defines the set of policies at this level of the config tree + # For organization policies, their canonical path is usually + # /Channel/// + Policies: + Readers: + Type: Signature + Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')" + Writers: + Type: Signature + Rule: "OR('Org2MSP.admin', 'Org2MSP.client')" + Admins: + Type: Signature + Rule: "OR('Org2MSP.admin')" + Endorsement: + Type: Signature + Rule: "OR('Org2MSP.peer')" + + AnchorPeers: + # AnchorPeers defines the location of peers which can be used + # for cross org gossip communication. Note, this value is only + # encoded in the genesis block in the Application section context + - Host: org2-peer1 + Port: 7051 + +################################################################################ +# +# SECTION: Capabilities +# +# - This section defines the capabilities of fabric network. This is a new +# concept as of v1.1.0 and should not be utilized in mixed networks with +# v1.0.x peers and orderers. Capabilities define features which must be +# present in a fabric binary for that binary to safely participate in the +# fabric network. For instance, if a new MSP type is added, newer binaries +# might recognize and validate the signatures from this type, while older +# binaries without this support would be unable to validate those +# transactions. This could lead to different versions of the fabric binaries +# having different world states. Instead, defining a capability for a channel +# informs those binaries without this capability that they must cease +# processing transactions until they have been upgraded. For v1.0.x if any +# capabilities are defined (including a map with all capabilities turned off) +# then the v1.0.x peer will deliberately crash. +# +################################################################################ +Capabilities: + # Channel capabilities apply to both the orderers and the peers and must be + # supported by both. + # Set the value of the capability to true to require it. + Channel: &ChannelCapabilities + # V2_0 capability ensures that orderers and peers behave according + # to v2.0 channel capabilities. Orderers and peers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 capability. + # Prior to enabling V2.0 channel capabilities, ensure that all + # orderers and peers on a channel are at v2.0.0 or later. + V2_0: true + + # Orderer capabilities apply only to the orderers, and may be safely + # used with prior release peers. + # Set the value of the capability to true to require it. + Orderer: &OrdererCapabilities + # V2_0 orderer capability ensures that orderers behave according + # to v2.0 orderer capabilities. Orderers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 orderer capability. + # Prior to enabling V2.0 orderer capabilities, ensure that all + # orderers on channel are at v2.0.0 or later. + V2_0: true + + # Application capabilities apply only to the peer network, and may be safely + # used with prior release orderers. + # Set the value of the capability to true to require it. + Application: &ApplicationCapabilities + # V2_0 application capability ensures that peers behave according + # to v2.0 application capabilities. Peers from + # prior releases would behave in an incompatible way, and are therefore + # not able to participate in channels at v2.0 application capability. + # Prior to enabling V2.0 application capabilities, ensure that all + # peers on channel are at v2.0.0 or later. + V2_0: true + +################################################################################ +# +# SECTION: Application +# +# - This section defines the values to encode into a config transaction or +# genesis block for application related parameters +# +################################################################################ +Application: &ApplicationDefaults + + # Organizations is the list of orgs which are defined as participants on + # the application side of the network + Organizations: + + # Policies defines the set of policies at this level of the config tree + # For Application policies, their canonical path is + # /Channel/Application/ + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + LifecycleEndorsement: + Type: Signature + Rule: "OR('Org1MSP.peer','Org2MSP.peer')" + Endorsement: + Type: Signature + Rule: "OR('Org1MSP.peer','Org2MSP.peer')" + + Capabilities: + <<: *ApplicationCapabilities +################################################################################ +# +# SECTION: Orderer +# +# - This section defines the values to encode into a config transaction or +# genesis block for orderer related parameters +# +################################################################################ +Orderer: &OrdererDefaults + + # Orderer Type: The orderer implementation to start + OrdererType: etcdraft + + EtcdRaft: + Consenters: + - Host: org0-orderer1 + Port: 6050 + ClientTLSCert: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/signcerts/cert.pem + ServerTLSCert: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/signcerts/cert.pem + - Host: org0-orderer2 + Port: 6050 + ClientTLSCert: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/signcerts/cert.pem + ServerTLSCert: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/signcerts/cert.pem + - Host: org0-orderer3 + Port: 6050 + ClientTLSCert: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/signcerts/cert.pem + ServerTLSCert: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/signcerts/cert.pem + + + # Options to be specified for all the etcd/raft nodes. The values here + # are the defaults for all new channels and can be modified on a + # per-channel basis via configuration updates. + Options: + # TickInterval is the time interval between two Node.Tick invocations. + #TickInterval: 500ms default + TickInterval: 2500ms + + # ElectionTick is the number of Node.Tick invocations that must pass + # between elections. That is, if a follower does not receive any + # message from the leader of current term before ElectionTick has + # elapsed, it will become candidate and start an election. + # ElectionTick must be greater than HeartbeatTick. + # ElectionTick: 10 default + ElectionTick: 5 + + # HeartbeatTick is the number of Node.Tick invocations that must + # pass between heartbeats. That is, a leader sends heartbeat + # messages to maintain its leadership every HeartbeatTick ticks. + HeartbeatTick: 1 + + # MaxInflightBlocks limits the max number of in-flight append messages + # during optimistic replication phase. + MaxInflightBlocks: 5 + + # SnapshotIntervalSize defines number of bytes per which a snapshot is taken + SnapshotIntervalSize: 16 MB + + # Batch Timeout: The amount of time to wait before creating a batch + BatchTimeout: 2s + + # Batch Size: Controls the number of messages batched into a block + BatchSize: + + # Max Message Count: The maximum number of messages to permit in a batch + MaxMessageCount: 10 + + # Absolute Max Bytes: The absolute maximum number of bytes allowed for + # the serialized messages in a batch. + AbsoluteMaxBytes: 99 MB + + # Preferred Max Bytes: The preferred maximum number of bytes allowed for + # the serialized messages in a batch. A message larger than the preferred + # max bytes will result in a batch larger than preferred max bytes. + PreferredMaxBytes: 512 KB + + # Organizations is the list of orgs which are defined as participants on + # the orderer side of the network + Organizations: + + # Policies defines the set of policies at this level of the config tree + # For Orderer policies, their canonical path is + # /Channel/Orderer/ + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + # BlockValidation specifies what signatures must be included in the block + # from the orderer for the peer to validate it. + BlockValidation: + Type: ImplicitMeta + Rule: "ANY Writers" + +################################################################################ +# +# CHANNEL +# +# This section defines the values to encode into a config transaction or +# genesis block for channel related parameters. +# +################################################################################ +Channel: &ChannelDefaults + # Policies defines the set of policies at this level of the config tree + # For Channel policies, their canonical path is + # /Channel/ + Policies: + # Who may invoke the 'Deliver' API + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + # Who may invoke the 'Broadcast' API + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + # By default, who may modify elements at this config level + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + + # Capabilities describes the channel level capabilities, see the + # dedicated Capabilities section elsewhere in this file for a full + # description + Capabilities: + <<: *ChannelCapabilities + +################################################################################ +# +# Profile +# +# - Different configuration profiles may be encoded here to be specified +# as parameters to the configtxgen tool +# +################################################################################ +Profiles: + + # test network profile with application (not system) channel. + TwoOrgsApplicationGenesis: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + Organizations: + - *OrdererOrg + Capabilities: *OrdererCapabilities + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + - *Org2 + Capabilities: *ApplicationCapabilities + + + # + # Unclear lineage for these profiles: nano-fab? + # + # TwoOrgsOrdererGenesis will construct a system channel as it has a Consortiums stanza, which is not + # compatible with osnadmin. + # + # @enyeart - which profile should be used for the kube test network? + # + TwoOrgsOrdererGenesis: + <<: *ChannelDefaults + Orderer: + <<: *OrdererDefaults + OrdererType: etcdraft + Organizations: + - *OrdererOrg + Capabilities: + <<: *OrdererCapabilities + Consortiums: + SampleConsortium: + Organizations: + - *Org1 + - *Org2 + TwoOrgsChannel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + - *Org2 + Capabilities: + <<: *ApplicationCapabilities + Org1Channel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + Capabilities: + <<: *ApplicationCapabilities + Org2Channel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Application: + <<: *ApplicationDefaults + Organizations: + - *Org2 + Capabilities: + <<: *ApplicationCapabilities diff --git a/test-network-k8s/config/org0/fabric-ecert-ca-server-config.yaml b/test-network-k8s/config/org0/fabric-ecert-ca-server-config.yaml new file mode 100644 index 00000000..eff91c34 --- /dev/null +++ b/test-network-k8s/config/org0/fabric-ecert-ca-server-config.yaml @@ -0,0 +1,506 @@ +############################################################################# +# This is a configuration file for the fabric-ca-server command. +# +# COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES +# ------------------------------------------------ +# Each configuration element can be overridden via command line +# arguments or environment variables. The precedence for determining +# the value of each element is as follows: +# 1) command line argument +# Examples: +# a) --port 443 +# To set the listening port +# b) --ca.keyfile ../mykey.pem +# To set the "keyfile" element in the "ca" section below; +# note the '.' separator character. +# 2) environment variable +# Examples: +# a) FABRIC_CA_SERVER_PORT=443 +# To set the listening port +# b) FABRIC_CA_SERVER_CA_KEYFILE="../mykey.pem" +# To set the "keyfile" element in the "ca" section below; +# note the '_' separator character. +# 3) configuration file +# 4) default value (if there is one) +# All default values are shown beside each element below. +# +# FILE NAME ELEMENTS +# ------------------ +# The value of all fields whose name ends with "file" or "files" are +# name or names of other files. +# For example, see "tls.certfile" and "tls.clientauth.certfiles". +# The value of each of these fields can be a simple filename, a +# relative path, or an absolute path. If the value is not an +# absolute path, it is interpretted as being relative to the location +# of this configuration file. +# +############################################################################# + +# Version of config file +version: 1.5.2 + +# Server's listening port (default: 7054) +port: 443 + +# Cross-Origin Resource Sharing (CORS) +cors: + enabled: false + origins: + - "*" + +# Enables debug logging (default: false) +debug: false + +# Size limit of an acceptable CRL in bytes (default: 512000) +crlsizelimit: 512000 + +############################################################################# +# TLS section for the server's listening port +# +# The following types are supported for client authentication: NoClientCert, +# RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, +# and RequireAndVerifyClientCert. +# +# Certfiles is a list of root certificate authorities that the server uses +# when verifying client certificates. +############################################################################# +tls: + # Enable TLS (default: false) + enabled: true + # TLS for the server's listening port + certfile: + keyfile: + clientauth: + type: noclientcert + certfiles: + +############################################################################# +# The CA section contains information related to the Certificate Authority +# including the name of the CA, which should be unique for all members +# of a blockchain network. It also includes the key and certificate files +# used when issuing enrollment certificates (ECerts) and transaction +# certificates (TCerts). +# The chainfile (if it exists) contains the certificate chain which +# should be trusted for this CA, where the 1st in the chain is always the +# root CA certificate. +############################################################################# +ca: + # Name of this CA + name: org0-ecert-ca + # Key file (is only used to import a private key into BCCSP) + keyfile: + # Certificate file (default: ca-cert.pem) + certfile: + # Chain file + chainfile: + +############################################################################# +# The gencrl REST endpoint is used to generate a CRL that contains revoked +# certificates. This section contains configuration options that are used +# during gencrl request processing. +############################################################################# +crl: + # Specifies expiration for the generated CRL. The number of hours + # specified by this property is added to the UTC time, the resulting time + # is used to set the 'Next Update' date of the CRL. + expiry: 24h + +############################################################################# +# The registry section controls how the fabric-ca-server does two things: +# 1) authenticates enrollment requests which contain a username and password +# (also known as an enrollment ID and secret). +# 2) once authenticated, retrieves the identity's attribute names and +# values which the fabric-ca-server optionally puts into TCerts +# which it issues for transacting on the Hyperledger Fabric blockchain. +# These attributes are useful for making access control decisions in +# chaincode. +# There are two main configuration options: +# 1) The fabric-ca-server is the registry. +# This is true if "ldap.enabled" in the ldap section below is false. +# 2) An LDAP server is the registry, in which case the fabric-ca-server +# calls the LDAP server to perform these tasks. +# This is true if "ldap.enabled" in the ldap section below is true, +# which means this "registry" section is ignored. +############################################################################# +registry: + # Maximum number of times a password/secret can be reused for enrollment + # (default: -1, which means there is no limit) + maxenrollments: -1 + + # Contains identity information which is used when LDAP is disabled + identities: + - name: rcaadmin + pass: rcaadminpw + type: client + affiliation: "" + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + +############################################################################# +# Database section +# Supported types are: "sqlite3", "postgres", and "mysql". +# The datasource value depends on the type. +# If the type is "sqlite3", the datasource value is a file name to use +# as the database store. Since "sqlite3" is an embedded database, it +# may not be used if you want to run the fabric-ca-server in a cluster. +# To run the fabric-ca-server in a cluster, you must choose "postgres" +# or "mysql". +############################################################################# +db: + type: sqlite3 + datasource: fabric-ca-server.db + tls: + enabled: false + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# LDAP section +# If LDAP is enabled, the fabric-ca-server calls LDAP to: +# 1) authenticate enrollment ID and secret (i.e. username and password) +# for enrollment requests; +# 2) To retrieve identity attributes +############################################################################# +ldap: + # Enables or disables the LDAP client (default: false) + # If this is set to true, the "registry" section is ignored. + enabled: false + # The URL of the LDAP server + url: ldap://:@:/ + # TLS configuration for the client connection to the LDAP server + tls: + certfiles: + client: + certfile: + keyfile: + # Attribute related configuration for mapping from LDAP entries to Fabric CA attributes + attribute: + # 'names' is an array of strings containing the LDAP attribute names which are + # requested from the LDAP server for an LDAP identity's entry + names: ['uid','member'] + # The 'converters' section is used to convert an LDAP entry to the value of + # a fabric CA attribute. + # For example, the following converts an LDAP 'uid' attribute + # whose value begins with 'revoker' to a fabric CA attribute + # named "hf.Revoker" with a value of "true" (because the boolean expression + # evaluates to true). + # converters: + # - name: hf.Revoker + # value: attr("uid") =~ "revoker*" + converters: + - name: + value: + # The 'maps' section contains named maps which may be referenced by the 'map' + # function in the 'converters' section to map LDAP responses to arbitrary values. + # For example, assume a user has an LDAP attribute named 'member' which has multiple + # values which are each a distinguished name (i.e. a DN). For simplicity, assume the + # values of the 'member' attribute are 'dn1', 'dn2', and 'dn3'. + # Further assume the following configuration. + # converters: + # - name: hf.Registrar.Roles + # value: map(attr("member"),"groups") + # maps: + # groups: + # - name: dn1 + # value: peer + # - name: dn2 + # value: client + # The value of the user's 'hf.Registrar.Roles' attribute is then computed to be + # "peer,client,dn3". This is because the value of 'attr("member")' is + # "dn1,dn2,dn3", and the call to 'map' with a 2nd argument of + # "group" replaces "dn1" with "peer" and "dn2" with "client". + maps: + groups: + - name: + value: + +############################################################################# +# Affiliations section. Fabric CA server can be bootstrapped with the +# affiliations specified in this section. Affiliations are specified as maps. +# For example: +# businessunit1: +# department1: +# - team1 +# businessunit2: +# - department2 +# - department3 +# +# Affiliations are hierarchical in nature. In the above example, +# department1 (used as businessunit1.department1) is the child of businessunit1. +# team1 (used as businessunit1.department1.team1) is the child of department1. +# department2 (used as businessunit2.department2) and department3 (businessunit2.department3) +# are children of businessunit2. +# Note: Affiliations are case sensitive except for the non-leaf affiliations +# (like businessunit1, department1, businessunit2) that are specified in the configuration file, +# which are always stored in lower case. +############################################################################# +affiliations: + org1: + - department1 + - department2 + org2: + - department1 + +############################################################################# +# Signing section +# +# The "default" subsection is used to sign enrollment certificates; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +# +# The "ca" profile subsection is used to sign intermediate CA certificates; +# the default expiration ("expiry" field) is "43800h" which is 5 years in hours. +# Note that "isca" is true, meaning that it issues a CA certificate. +# A maxpathlen of 0 means that the intermediate CA cannot issue other +# intermediate CA certificates, though it can still issue end entity certificates. +# (See RFC 5280, section 4.2.1.9) +# +# The "tls" profile subsection is used to sign TLS certificate requests; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +############################################################################# +signing: + default: + usage: + - digital signature + expiry: 8760h + profiles: + ca: + usage: + - cert sign + - crl sign + expiry: 43800h + caconstraint: + isca: true + maxpathlen: 0 + tls: + usage: + - signing + - key encipherment + - server auth + - client auth + - key agreement + expiry: 8760h + +########################################################################### +# Certificate Signing Request (CSR) section. +# This controls the creation of the root CA certificate. +# The expiration for the root CA certificate is configured with the +# "ca.expiry" field below, whose default value is "131400h" which is +# 15 years in hours. +# The pathlength field is used to limit CA certificate hierarchy as described +# in section 4.2.1.9 of RFC 5280. +# Examples: +# 1) No pathlength value means no limit is requested. +# 2) pathlength == 1 means a limit of 1 is requested which is the default for +# a root CA. This means the root CA can issue intermediate CA certificates, +# but these intermediate CAs may not in turn issue other CA certificates +# though they can still issue end entity certificates. +# 3) pathlength == 0 means a limit of 0 is requested; +# this is the default for an intermediate CA, which means it can not issue +# CA certificates though it can still issue end entity certificates. +########################################################################### +csr: + cn: fabric-ca-server + keyrequest: + algo: ecdsa + size: 256 + names: + - C: US + ST: "North Carolina" + L: + O: Hyperledger + OU: Fabric + hosts: + - localhost + - 127.0.0.1 + - org0-ecert-ca + - org0-ecert-ca.test-network.svc.cluster.local + ca: + expiry: 131400h + pathlength: 1 + +########################################################################### +# Each CA can issue both X509 enrollment certificate as well as Idemix +# Credential. This section specifies configuration for the issuer component +# that is responsible for issuing Idemix credentials. +########################################################################### +idemix: + # Specifies pool size for revocation handles. A revocation handle is an unique identifier of an + # Idemix credential. The issuer will create a pool revocation handles of this specified size. When + # a credential is requested, issuer will get handle from the pool and assign it to the credential. + # Issuer will repopulate the pool with new handles when the last handle in the pool is used. + # A revocation handle and credential revocation information (CRI) are used to create non revocation proof + # by the prover to prove to the verifier that her credential is not revoked. + rhpoolsize: 1000 + + # The Idemix credential issuance is a two step process. First step is to get a nonce from the issuer + # and second step is send credential request that is constructed using the nonce to the isuser to + # request a credential. This configuration property specifies expiration for the nonces. By default is + # nonces expire after 15 seconds. The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration). + nonceexpiration: 15s + + # Specifies interval at which expired nonces are removed from datastore. Default value is 15 minutes. + # The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration) + noncesweepinterval: 15m + +############################################################################# +# BCCSP (BlockChain Crypto Service Provider) section is used to select which +# crypto library implementation to use +############################################################################# +bccsp: + default: SW + sw: + hash: SHA2 + security: 256 + filekeystore: + # The directory used for the software file-based keystore + keystore: msp/keystore + +############################################################################# +# Multi CA section +# +# Each Fabric CA server contains one CA by default. This section is used +# to configure multiple CAs in a single server. +# +# 1) --cacount +# Automatically generate non-default CAs. The names of these +# additional CAs are "ca1", "ca2", ... "caN", where "N" is +# This is particularly useful in a development environment to quickly set up +# multiple CAs. Note that, this config option is not applicable to intermediate CA server +# i.e., Fabric CA server that is started with intermediate.parentserver.url config +# option (-u command line option) +# +# 2) --cafiles +# For each CA config file in the list, generate a separate signing CA. Each CA +# config file in this list MAY contain all of the same elements as are found in +# the server config file except port, debug, and tls sections. +# +# Examples: +# fabric-ca-server start -b admin:adminpw --cacount 2 +# +# fabric-ca-server start -b admin:adminpw --cafiles ca/ca1/fabric-ca-server-config.yaml +# --cafiles ca/ca2/fabric-ca-server-config.yaml +# +############################################################################# + +cacount: + +cafiles: + +############################################################################# +# Intermediate CA section +# +# The relationship between servers and CAs is as follows: +# 1) A single server process may contain or function as one or more CAs. +# This is configured by the "Multi CA section" above. +# 2) Each CA is either a root CA or an intermediate CA. +# 3) Each intermediate CA has a parent CA which is either a root CA or another intermediate CA. +# +# This section pertains to configuration of #2 and #3. +# If the "intermediate.parentserver.url" property is set, +# then this is an intermediate CA with the specified parent +# CA. +# +# parentserver section +# url - The URL of the parent server +# caname - Name of the CA to enroll within the server +# +# enrollment section used to enroll intermediate CA with parent CA +# profile - Name of the signing profile to use in issuing the certificate +# label - Label to use in HSM operations +# +# tls section for secure socket connection +# certfiles - PEM-encoded list of trusted root certificate files +# client: +# certfile - PEM-encoded certificate file for when client authentication +# is enabled on server +# keyfile - PEM-encoded key file for when client authentication +# is enabled on server +############################################################################# +intermediate: + parentserver: + url: + caname: + + enrollment: + hosts: + profile: + label: + + tls: + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# CA configuration section +# +# Configure the number of incorrect password attempts are allowed for +# identities. By default, the value of 'passwordattempts' is 10, which +# means that 10 incorrect password attempts can be made before an identity get +# locked out. +############################################################################# +cfg: + identities: + passwordattempts: 10 + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9443 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # require client certificate authentication to access all resources + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushsed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd merics + prefix: server diff --git a/test-network-k8s/config/org0/fabric-tls-ca-server-config.yaml b/test-network-k8s/config/org0/fabric-tls-ca-server-config.yaml new file mode 100644 index 00000000..b574e72b --- /dev/null +++ b/test-network-k8s/config/org0/fabric-tls-ca-server-config.yaml @@ -0,0 +1,496 @@ +############################################################################# +# This is a configuration file for the fabric-ca-server command. +# +# COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES +# ------------------------------------------------ +# Each configuration element can be overridden via command line +# arguments or environment variables. The precedence for determining +# the value of each element is as follows: +# 1) command line argument +# Examples: +# a) --port 443 +# To set the listening port +# b) --ca.keyfile ../mykey.pem +# To set the "keyfile" element in the "ca" section below; +# note the '.' separator character. +# 2) environment variable +# Examples: +# a) FABRIC_CA_SERVER_PORT=443 +# To set the listening port +# b) FABRIC_CA_SERVER_CA_KEYFILE="../mykey.pem" +# To set the "keyfile" element in the "ca" section below; +# note the '_' separator character. +# 3) configuration file +# 4) default value (if there is one) +# All default values are shown beside each element below. +# +# FILE NAME ELEMENTS +# ------------------ +# The value of all fields whose name ends with "file" or "files" are +# name or names of other files. +# For example, see "tls.certfile" and "tls.clientauth.certfiles". +# The value of each of these fields can be a simple filename, a +# relative path, or an absolute path. If the value is not an +# absolute path, it is interpretted as being relative to the location +# of this configuration file. +# +############################################################################# + +# Version of config file +version: 1.5.2 + +# Server's listening port (default: 7054) +port: 443 + +# Cross-Origin Resource Sharing (CORS) +cors: + enabled: false + origins: + - "*" + +# Enables debug logging (default: false) +debug: false + +# Size limit of an acceptable CRL in bytes (default: 512000) +crlsizelimit: 512000 + +############################################################################# +# TLS section for the server's listening port +# +# The following types are supported for client authentication: NoClientCert, +# RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, +# and RequireAndVerifyClientCert. +# +# Certfiles is a list of root certificate authorities that the server uses +# when verifying client certificates. +############################################################################# +tls: + # Enable TLS (default: false) + enabled: true + # TLS for the server's listening port + certfile: + keyfile: + clientauth: + type: noclientcert + certfiles: + +############################################################################# +# The CA section contains information related to the Certificate Authority +# including the name of the CA, which should be unique for all members +# of a blockchain network. It also includes the key and certificate files +# used when issuing enrollment certificates (ECerts) and transaction +# certificates (TCerts). +# The chainfile (if it exists) contains the certificate chain which +# should be trusted for this CA, where the 1st in the chain is always the +# root CA certificate. +############################################################################# +ca: + # Name of this CA + name: org0-tls-ca + # Key file (is only used to import a private key into BCCSP) + keyfile: + # Certificate file (default: ca-cert.pem) + certfile: + # Chain file + chainfile: + +############################################################################# +# The gencrl REST endpoint is used to generate a CRL that contains revoked +# certificates. This section contains configuration options that are used +# during gencrl request processing. +############################################################################# +crl: + # Specifies expiration for the generated CRL. The number of hours + # specified by this property is added to the UTC time, the resulting time + # is used to set the 'Next Update' date of the CRL. + expiry: 24h + +############################################################################# +# The registry section controls how the fabric-ca-server does two things: +# 1) authenticates enrollment requests which contain a username and password +# (also known as an enrollment ID and secret). +# 2) once authenticated, retrieves the identity's attribute names and +# values which the fabric-ca-server optionally puts into TCerts +# which it issues for transacting on the Hyperledger Fabric blockchain. +# These attributes are useful for making access control decisions in +# chaincode. +# There are two main configuration options: +# 1) The fabric-ca-server is the registry. +# This is true if "ldap.enabled" in the ldap section below is false. +# 2) An LDAP server is the registry, in which case the fabric-ca-server +# calls the LDAP server to perform these tasks. +# This is true if "ldap.enabled" in the ldap section below is true, +# which means this "registry" section is ignored. +############################################################################# +registry: + # Maximum number of times a password/secret can be reused for enrollment + # (default: -1, which means there is no limit) + maxenrollments: -1 + + # Contains identity information which is used when LDAP is disabled + identities: + - name: tlsadmin + pass: tlsadminpw + type: client + affiliation: "" + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + +############################################################################# +# Database section +# Supported types are: "sqlite3", "postgres", and "mysql". +# The datasource value depends on the type. +# If the type is "sqlite3", the datasource value is a file name to use +# as the database store. Since "sqlite3" is an embedded database, it +# may not be used if you want to run the fabric-ca-server in a cluster. +# To run the fabric-ca-server in a cluster, you must choose "postgres" +# or "mysql". +############################################################################# +db: + type: sqlite3 + datasource: fabric-ca-server.db + tls: + enabled: false + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# LDAP section +# If LDAP is enabled, the fabric-ca-server calls LDAP to: +# 1) authenticate enrollment ID and secret (i.e. username and password) +# for enrollment requests; +# 2) To retrieve identity attributes +############################################################################# +ldap: + # Enables or disables the LDAP client (default: false) + # If this is set to true, the "registry" section is ignored. + enabled: false + # The URL of the LDAP server + url: ldap://:@:/ + # TLS configuration for the client connection to the LDAP server + tls: + certfiles: + client: + certfile: + keyfile: + # Attribute related configuration for mapping from LDAP entries to Fabric CA attributes + attribute: + # 'names' is an array of strings containing the LDAP attribute names which are + # requested from the LDAP server for an LDAP identity's entry + names: ['uid','member'] + # The 'converters' section is used to convert an LDAP entry to the value of + # a fabric CA attribute. + # For example, the following converts an LDAP 'uid' attribute + # whose value begins with 'revoker' to a fabric CA attribute + # named "hf.Revoker" with a value of "true" (because the boolean expression + # evaluates to true). + # converters: + # - name: hf.Revoker + # value: attr("uid") =~ "revoker*" + converters: + - name: + value: + # The 'maps' section contains named maps which may be referenced by the 'map' + # function in the 'converters' section to map LDAP responses to arbitrary values. + # For example, assume a user has an LDAP attribute named 'member' which has multiple + # values which are each a distinguished name (i.e. a DN). For simplicity, assume the + # values of the 'member' attribute are 'dn1', 'dn2', and 'dn3'. + # Further assume the following configuration. + # converters: + # - name: hf.Registrar.Roles + # value: map(attr("member"),"groups") + # maps: + # groups: + # - name: dn1 + # value: peer + # - name: dn2 + # value: client + # The value of the user's 'hf.Registrar.Roles' attribute is then computed to be + # "peer,client,dn3". This is because the value of 'attr("member")' is + # "dn1,dn2,dn3", and the call to 'map' with a 2nd argument of + # "group" replaces "dn1" with "peer" and "dn2" with "client". + maps: + groups: + - name: + value: + +############################################################################# +# Affiliations section. Fabric CA server can be bootstrapped with the +# affiliations specified in this section. Affiliations are specified as maps. +# For example: +# businessunit1: +# department1: +# - team1 +# businessunit2: +# - department2 +# - department3 +# +# Affiliations are hierarchical in nature. In the above example, +# department1 (used as businessunit1.department1) is the child of businessunit1. +# team1 (used as businessunit1.department1.team1) is the child of department1. +# department2 (used as businessunit2.department2) and department3 (businessunit2.department3) +# are children of businessunit2. +# Note: Affiliations are case sensitive except for the non-leaf affiliations +# (like businessunit1, department1, businessunit2) that are specified in the configuration file, +# which are always stored in lower case. +############################################################################# +affiliations: + org1: + - department1 + - department2 + org2: + - department1 + +############################################################################# +# Signing section +# +# The "default" subsection is used to sign enrollment certificates; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +# +# The "ca" profile subsection is used to sign intermediate CA certificates; +# the default expiration ("expiry" field) is "43800h" which is 5 years in hours. +# Note that "isca" is true, meaning that it issues a CA certificate. +# A maxpathlen of 0 means that the intermediate CA cannot issue other +# intermediate CA certificates, though it can still issue end entity certificates. +# (See RFC 5280, section 4.2.1.9) +# +# The "tls" profile subsection is used to sign TLS certificate requests; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +############################################################################# +signing: + default: + authremote: {} + caconstraint: {} + expiry: 8760h + usage: + - signing + - key encipherment + - server auth + - client auth + - key agreement + profiles: null + +########################################################################### +# Certificate Signing Request (CSR) section. +# This controls the creation of the root CA certificate. +# The expiration for the root CA certificate is configured with the +# "ca.expiry" field below, whose default value is "131400h" which is +# 15 years in hours. +# The pathlength field is used to limit CA certificate hierarchy as described +# in section 4.2.1.9 of RFC 5280. +# Examples: +# 1) No pathlength value means no limit is requested. +# 2) pathlength == 1 means a limit of 1 is requested which is the default for +# a root CA. This means the root CA can issue intermediate CA certificates, +# but these intermediate CAs may not in turn issue other CA certificates +# though they can still issue end entity certificates. +# 3) pathlength == 0 means a limit of 0 is requested; +# this is the default for an intermediate CA, which means it can not issue +# CA certificates though it can still issue end entity certificates. +########################################################################### +csr: + cn: fabric-ca-server + keyrequest: + algo: ecdsa + size: 256 + names: + - C: US + ST: "North Carolina" + L: + O: Hyperledger + OU: Fabric + hosts: + - localhost + - 127.0.0.1 + - org0-tls-ca + - org0-tls-ca.test-network.svc.cluster.local + ca: + expiry: 131400h + pathlength: 1 + +########################################################################### +# Each CA can issue both X509 enrollment certificate as well as Idemix +# Credential. This section specifies configuration for the issuer component +# that is responsible for issuing Idemix credentials. +########################################################################### +idemix: + # Specifies pool size for revocation handles. A revocation handle is an unique identifier of an + # Idemix credential. The issuer will create a pool revocation handles of this specified size. When + # a credential is requested, issuer will get handle from the pool and assign it to the credential. + # Issuer will repopulate the pool with new handles when the last handle in the pool is used. + # A revocation handle and credential revocation information (CRI) are used to create non revocation proof + # by the prover to prove to the verifier that her credential is not revoked. + rhpoolsize: 1000 + + # The Idemix credential issuance is a two step process. First step is to get a nonce from the issuer + # and second step is send credential request that is constructed using the nonce to the isuser to + # request a credential. This configuration property specifies expiration for the nonces. By default is + # nonces expire after 15 seconds. The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration). + nonceexpiration: 15s + + # Specifies interval at which expired nonces are removed from datastore. Default value is 15 minutes. + # The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration) + noncesweepinterval: 15m + +############################################################################# +# BCCSP (BlockChain Crypto Service Provider) section is used to select which +# crypto library implementation to use +############################################################################# +bccsp: + default: SW + sw: + hash: SHA2 + security: 256 + filekeystore: + # The directory used for the software file-based keystore + keystore: msp/keystore + +############################################################################# +# Multi CA section +# +# Each Fabric CA server contains one CA by default. This section is used +# to configure multiple CAs in a single server. +# +# 1) --cacount +# Automatically generate non-default CAs. The names of these +# additional CAs are "ca1", "ca2", ... "caN", where "N" is +# This is particularly useful in a development environment to quickly set up +# multiple CAs. Note that, this config option is not applicable to intermediate CA server +# i.e., Fabric CA server that is started with intermediate.parentserver.url config +# option (-u command line option) +# +# 2) --cafiles +# For each CA config file in the list, generate a separate signing CA. Each CA +# config file in this list MAY contain all of the same elements as are found in +# the server config file except port, debug, and tls sections. +# +# Examples: +# fabric-ca-server start -b admin:adminpw --cacount 2 +# +# fabric-ca-server start -b admin:adminpw --cafiles ca/ca1/fabric-ca-server-config.yaml +# --cafiles ca/ca2/fabric-ca-server-config.yaml +# +############################################################################# + +cacount: + +cafiles: + +############################################################################# +# Intermediate CA section +# +# The relationship between servers and CAs is as follows: +# 1) A single server process may contain or function as one or more CAs. +# This is configured by the "Multi CA section" above. +# 2) Each CA is either a root CA or an intermediate CA. +# 3) Each intermediate CA has a parent CA which is either a root CA or another intermediate CA. +# +# This section pertains to configuration of #2 and #3. +# If the "intermediate.parentserver.url" property is set, +# then this is an intermediate CA with the specified parent +# CA. +# +# parentserver section +# url - The URL of the parent server +# caname - Name of the CA to enroll within the server +# +# enrollment section used to enroll intermediate CA with parent CA +# profile - Name of the signing profile to use in issuing the certificate +# label - Label to use in HSM operations +# +# tls section for secure socket connection +# certfiles - PEM-encoded list of trusted root certificate files +# client: +# certfile - PEM-encoded certificate file for when client authentication +# is enabled on server +# keyfile - PEM-encoded key file for when client authentication +# is enabled on server +############################################################################# +intermediate: + parentserver: + url: + caname: + + enrollment: + hosts: + profile: + label: + + tls: + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# CA configuration section +# +# Configure the number of incorrect password attempts are allowed for +# identities. By default, the value of 'passwordattempts' is 10, which +# means that 10 incorrect password attempts can be made before an identity get +# locked out. +############################################################################# +cfg: + identities: + passwordattempts: 10 + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9444 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # require client certificate authentication to access all resources + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushsed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd merics + prefix: server diff --git a/test-network-k8s/config/org0/orderer.yaml b/test-network-k8s/config/org0/orderer.yaml new file mode 100644 index 00000000..c8e25a07 --- /dev/null +++ b/test-network-k8s/config/org0/orderer.yaml @@ -0,0 +1,420 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + + +--- +################################################################################ +# +# Orderer Configuration +# +# - This controls the type and configuration of the orderer. +# +################################################################################ +General: + # Listen address: The IP on which to bind to listen. + ListenAddress: 0.0.0.0 + + # Listen port: The port on which to bind to listen. + ListenPort: 6050 + + # TLS: TLS settings for the GRPC server. + TLS: + # Require server-side TLS + Enabled: false + # PrivateKey governs the file location of the private key of the TLS certificate. + PrivateKey: tls/server.key + # Certificate governs the file location of the server TLS certificate. + Certificate: tls/server.crt + # RootCAs contains a list of additional root certificates used for verifying certificates + # of other orderer nodes during outbound connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + RootCAs: + - tls/ca.crt + # Require client certificates / mutual TLS for inbound connections. + ClientAuthRequired: false + # If mutual TLS is enabled, ClientRootCAs contains a list of additional root certificates + # used for verifying certificates of client connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + ClientRootCAs: + # Keepalive settings for the GRPC server. + Keepalive: + # ServerMinInterval is the minimum permitted time between client pings. + # If clients send pings more frequently, the server will + # disconnect them. + ServerMinInterval: 60s + # ServerInterval is the time between pings to clients. + ServerInterval: 7200s + # ServerTimeout is the duration the server waits for a response from + # a client before closing the connection. + ServerTimeout: 20s + # Cluster settings for ordering service nodes that communicate with other ordering service nodes + # such as Raft based ordering service. + Cluster: + # SendBufferSize is the maximum number of messages in the egress buffer. + # Consensus messages are dropped if the buffer is full, and transaction + # messages are waiting for space to be freed. + SendBufferSize: 10 + + # ClientCertificate governs the file location of the client TLS certificate + # used to establish mutual TLS connections with other ordering service nodes. + # If not set, the server General.TLS.Certificate is re-used. + ClientCertificate: + # ClientPrivateKey governs the file location of the private key of the client TLS certificate. + # If not set, the server General.TLS.PrivateKey is re-used. + ClientPrivateKey: + + # The below 4 properties should be either set together, or be unset together. + # If they are set, then the orderer node uses a separate listener for intra-cluster + # communication. If they are unset, then the general orderer listener is used. + # This is useful if you want to use a different TLS server certificates on the + # client-facing and the intra-cluster listeners. + + # ListenPort defines the port on which the cluster listens to connections. + ListenPort: + # ListenAddress defines the IP on which to listen to intra-cluster communication. + ListenAddress: + # ServerCertificate defines the file location of the server TLS certificate used for intra-cluster + # communication. + ServerCertificate: + # ServerPrivateKey defines the file location of the private key of the TLS certificate. + ServerPrivateKey: + + # Bootstrap method: The method by which to obtain the bootstrap block + # system channel is specified. The option can be one of: + # "file" - path to a file containing the genesis block or config block of system channel + # "none" - allows an orderer to start without a system channel configuration + BootstrapMethod: none + + # Bootstrap file: The file containing the bootstrap block to use when + # initializing the orderer system channel and BootstrapMethod is set to + # "file". The bootstrap file can be the genesis block, and it can also be + # a config block for late bootstrap of some consensus methods like Raft. + # Generate a genesis block by updating $FABRIC_CFG_PATH/configtx.yaml and + # using configtxgen command with "-outputBlock" option. + # Defaults to file "genesisblock" (in $FABRIC_CFG_PATH directory) if not specified. + BootstrapFile: + + # LocalMSPDir is where to find the private crypto material needed by the + # orderer. It is set relative here as a default for dev environments but + # should be changed to the real location in production. + LocalMSPDir: msp + + # LocalMSPID is the identity to register the local MSP material with the MSP + # manager. IMPORTANT: The local MSP ID of an orderer needs to match the MSP + # ID of one of the organizations defined in the orderer system channel's + # /Channel/Orderer configuration. The sample organization defined in the + # sample configuration provided has an MSP ID of "SampleOrg". + LocalMSPID: SampleOrg + + # Enable an HTTP service for Go "pprof" profiling as documented at: + # https://golang.org/pkg/net/http/pprof + Profile: + Enabled: false + Address: 0.0.0.0:6060 + + # BCCSP configures the blockchain crypto service providers. + BCCSP: + # Default specifies the preferred blockchain crypto service provider + # to use. If the preferred provider is not available, the software + # based provider ("SW") will be used. + # Valid providers are: + # - SW: a software based crypto provider + # - PKCS11: a CA hardware security module crypto provider. + Default: SW + + # SW configures the software based blockchain crypto provider. + SW: + # TODO: The default Hash and Security level needs refactoring to be + # fully configurable. Changing these defaults requires coordination + # SHA2 is hardcoded in several places, not only BCCSP + Hash: SHA2 + Security: 256 + # Location of key store. If this is unset, a location will be + # chosen using: 'LocalMSPDir'/keystore + FileKeyStore: + KeyStore: + + # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) + PKCS11: + # Location of the PKCS11 module library + Library: + # Token Label + Label: + # User PIN + Pin: + Hash: + Security: + FileKeyStore: + KeyStore: + + # Authentication contains configuration parameters related to authenticating + # client messages + Authentication: + # the acceptable difference between the current server time and the + # client's time as specified in a client request message + TimeWindow: 15m + + +################################################################################ +# +# SECTION: File Ledger +# +# - This section applies to the configuration of the file ledger. +# +################################################################################ +FileLedger: + + # Location: The directory to store the blocks in. + Location: /var/hyperledger/production/orderer + +################################################################################ +# +# SECTION: Kafka +# +# - This section applies to the configuration of the Kafka-based orderer, and +# its interaction with the Kafka cluster. +# +################################################################################ +Kafka: + + # Retry: What do if a connection to the Kafka cluster cannot be established, + # or if a metadata request to the Kafka cluster needs to be repeated. + Retry: + # When a new channel is created, or when an existing channel is reloaded + # (in case of a just-restarted orderer), the orderer interacts with the + # Kafka cluster in the following ways: + # 1. It creates a Kafka producer (writer) for the Kafka partition that + # corresponds to the channel. + # 2. It uses that producer to post a no-op CONNECT message to that + # partition + # 3. It creates a Kafka consumer (reader) for that partition. + # If any of these steps fail, they will be re-attempted every + # for a total of , and then every + # for a total of until they succeed. + # Note that the orderer will be unable to write to or read from a + # channel until all of the steps above have been completed successfully. + ShortInterval: 5s + ShortTotal: 10m + LongInterval: 5m + LongTotal: 12h + # Affects the socket timeouts when waiting for an initial connection, a + # response, or a transmission. See Config.Net for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + NetworkTimeouts: + DialTimeout: 10s + ReadTimeout: 10s + WriteTimeout: 10s + # Affects the metadata requests when the Kafka cluster is in the middle + # of a leader election.See Config.Metadata for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Metadata: + RetryBackoff: 250ms + RetryMax: 3 + # What to do if posting a message to the Kafka cluster fails. See + # Config.Producer for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Producer: + RetryBackoff: 100ms + RetryMax: 3 + # What to do if reading from the Kafka cluster fails. See + # Config.Consumer for more info: + # https://godoc.org/github.com/Shopify/sarama#Config + Consumer: + RetryBackoff: 2s + # Settings to use when creating Kafka topics. Only applies when + # Kafka.Version is v0.10.1.0 or higher + Topic: + # The number of Kafka brokers across which to replicate the topic + ReplicationFactor: 3 + # Verbose: Enable logging for interactions with the Kafka cluster. + Verbose: false + + # TLS: TLS settings for the orderer's connection to the Kafka cluster. + TLS: + + # Enabled: Use TLS when connecting to the Kafka cluster. + Enabled: false + + # PrivateKey: PEM-encoded private key the orderer will use for + # authentication. + PrivateKey: + # As an alternative to specifying the PrivateKey here, uncomment the + # following "File" key and specify the file name from which to load the + # value of PrivateKey. + #File: path/to/PrivateKey + + # Certificate: PEM-encoded signed public key certificate the orderer will + # use for authentication. + Certificate: + # As an alternative to specifying the Certificate here, uncomment the + # following "File" key and specify the file name from which to load the + # value of Certificate. + #File: path/to/Certificate + + # RootCAs: PEM-encoded trusted root certificates used to validate + # certificates from the Kafka cluster. + RootCAs: + # As an alternative to specifying the RootCAs here, uncomment the + # following "File" key and specify the file name from which to load the + # value of RootCAs. + #File: path/to/RootCAs + + # SASLPlain: Settings for using SASL/PLAIN authentication with Kafka brokers + SASLPlain: + # Enabled: Use SASL/PLAIN to authenticate with Kafka brokers + Enabled: false + # User: Required when Enabled is set to true + User: + # Password: Required when Enabled is set to true + Password: + + # Kafka protocol version used to communicate with the Kafka cluster brokers + # (defaults to 0.10.2.0 if not specified) + Version: + +################################################################################ +# +# Debug Configuration +# +# - This controls the debugging options for the orderer +# +################################################################################ +Debug: + + # BroadcastTraceDir when set will cause each request to the Broadcast service + # for this orderer to be written to a file in this directory + BroadcastTraceDir: + + # DeliverTraceDir when set will cause each request to the Deliver service + # for this orderer to be written to a file in this directory + DeliverTraceDir: + +################################################################################ +# +# Operations Configuration +# +# - This configures the operations server endpoint for the orderer +# +################################################################################ +Operations: + # host and port for the operations server + ListenAddress: 0.0.0.0:8443 + + # TLS configuration for the operations endpoint + TLS: + # TLS enabled + Enabled: false + + # Certificate is the location of the PEM encoded TLS certificate + Certificate: + + # PrivateKey points to the location of the PEM-encoded key + PrivateKey: + + # Most operations service endpoints require client authentication when TLS + # is enabled. ClientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + ClientAuthRequired: false + + # Paths to PEM encoded ca certificates to trust for client authentication + ClientRootCAs: [] + +################################################################################ +# +# Metrics Configuration +# +# - This configures metrics collection for the orderer +# +################################################################################ +Metrics: + # The metrics provider is one of statsd, prometheus, or disabled + Provider: disabled + + # The statsd configuration + Statsd: + # network type: tcp or udp + Network: udp + + # the statsd server address + Address: 127.0.0.1:8125 + + # The interval at which locally cached counters and gauges are pushed + # to statsd; timings are pushed immediately + WriteInterval: 30s + + # The prefix is prepended to all emitted statsd metrics + Prefix: + +################################################################################ +# +# Admin Configuration +# +# - This configures the admin server endpoint for the orderer +# +################################################################################ +Admin: + # host and port for the admin server + ListenAddress: 0.0.0.0:9443 + + # TLS configuration for the admin endpoint + TLS: + # TLS enabled + Enabled: false + + # Certificate is the location of the PEM encoded TLS certificate + Certificate: + + # PrivateKey points to the location of the PEM-encoded key + PrivateKey: + + # Most admin service endpoints require client authentication when TLS + # is enabled. ClientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + # + # NOTE: When TLS is enabled, the admin endpoint requires mutual TLS. The + # orderer will panic on startup if this value is set to false. + ClientAuthRequired: true + + # Paths to PEM encoded ca certificates to trust for client authentication + ClientRootCAs: [] + +################################################################################ +# +# Channel participation API Configuration +# +# - This provides the channel participation API configuration for the orderer. +# - Channel participation uses the ListenAddress and TLS settings of the Admin +# service. +# +################################################################################ +ChannelParticipation: + # Channel participation API is enabled. + Enabled: true + + # The maximum size of the request body when joining a channel. + MaxRequestBodySize: 1 MB + + +################################################################################ +# +# Consensus Configuration +# +# - This section contains config options for a consensus plugin. It is opaque +# to orderer, and completely up to consensus implementation to make use of. +# +################################################################################ +Consensus: + # The allowed key-value pairs here depend on consensus plugin. For etcd/raft, + # we use following options: + + # WALDir specifies the location at which Write Ahead Logs for etcd/raft are + # stored. Each channel will have its own subdir named after channel ID. + WALDir: /var/hyperledger/production/orderer/etcdraft/wal + + # SnapDir specifies the location at which snapshots for etcd/raft are + # stored. Each channel will have its own subdir named after channel ID. + SnapDir: /var/hyperledger/production/orderer/etcdraft/snapshot diff --git a/test-network-k8s/config/org1/core.yaml b/test-network-k8s/config/org1/core.yaml new file mode 100644 index 00000000..ca60ae52 --- /dev/null +++ b/test-network-k8s/config/org1/core.yaml @@ -0,0 +1,759 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################### +# +# Peer section +# +############################################################################### +peer: + + # The peer id provides a name for this peer instance and is used when + # naming docker resources. + id: jdoe + + # The networkId allows for logical separation of networks and is used when + # naming docker resources. + networkId: dev + + # The Address at local network interface this Peer will listen on. + # By default, it will listen on all network interfaces + listenAddress: 0.0.0.0:7051 + + # The endpoint this peer uses to listen for inbound chaincode connections. + # If this is commented-out, the listen address is selected to be + # the peer's address (see below) with port 7052 + # chaincodeListenAddress: 0.0.0.0:7052 + + # The endpoint the chaincode for this peer uses to connect to the peer. + # If this is not specified, the chaincodeListenAddress address is selected. + # And if chaincodeListenAddress is not specified, address is selected from + # peer address (see below). If specified peer address is invalid then it + # will fallback to the auto detected IP (local IP) regardless of the peer + # addressAutoDetect value. + # chaincodeAddress: 0.0.0.0:7052 + + # When used as peer config, this represents the endpoint to other peers + # in the same organization. For peers in other organization, see + # gossip.externalEndpoint for more info. + # When used as CLI config, this means the peer's endpoint to interact with + address: 0.0.0.0:7051 + + # Whether the Peer should programmatically determine its address + # This case is useful for docker containers. + # When set to true, will override peer address. + addressAutoDetect: false + + # Keepalive settings for peer server and clients + keepalive: + # Interval is the duration after which if the server does not see + # any activity from the client it pings the client to see if it's alive + interval: 7200s + # Timeout is the duration the server waits for a response + # from the client after sending a ping before closing the connection + timeout: 20s + # MinInterval is the minimum permitted time between client pings. + # If clients send pings more frequently, the peer server will + # disconnect them + minInterval: 60s + # Client keepalive settings for communicating with other peer nodes + client: + # Interval is the time between pings to peer nodes. This must + # greater than or equal to the minInterval specified by peer + # nodes + interval: 60s + # Timeout is the duration the client waits for a response from + # peer nodes before closing the connection + timeout: 20s + # DeliveryClient keepalive settings for communication with ordering + # nodes. + deliveryClient: + # Interval is the time between pings to ordering nodes. This must + # greater than or equal to the minInterval specified by ordering + # nodes. + interval: 60s + # Timeout is the duration the client waits for a response from + # ordering nodes before closing the connection + timeout: 20s + + + # Gossip related configuration + gossip: + # Bootstrap set to initialize gossip with. + # This is a list of other peers that this peer reaches out to at startup. + # Important: The endpoints here have to be endpoints of peers in the same + # organization, because the peer would refuse connecting to these endpoints + # unless they are in the same organization as the peer. + bootstrap: 127.0.0.1:7051 + + # NOTE: orgLeader and useLeaderElection parameters are mutual exclusive. + # Setting both to true would result in the termination of the peer + # since this is undefined state. If the peers are configured with + # useLeaderElection=false, make sure there is at least 1 peer in the + # organization that its orgLeader is set to true. + + # Defines whenever peer will initialize dynamic algorithm for + # "leader" selection, where leader is the peer to establish + # connection with ordering service and use delivery protocol + # to pull ledger blocks from ordering service. + useLeaderElection: false + # Statically defines peer to be an organization "leader", + # where this means that current peer will maintain connection + # with ordering service and disseminate block across peers in + # its own organization. Multiple peers or all peers in an organization + # may be configured as org leaders, so that they all pull + # blocks directly from ordering service. + orgLeader: true + + # Interval for membershipTracker polling + membershipTrackerInterval: 5s + + # Overrides the endpoint that the peer publishes to peers + # in its organization. For peers in foreign organizations + # see 'externalEndpoint' + endpoint: + # Maximum count of blocks stored in memory + maxBlockCountToStore: 10 + # Max time between consecutive message pushes(unit: millisecond) + maxPropagationBurstLatency: 10ms + # Max number of messages stored until a push is triggered to remote peers + maxPropagationBurstSize: 10 + # Number of times a message is pushed to remote peers + propagateIterations: 1 + # Number of peers selected to push messages to + propagatePeerNum: 3 + # Determines frequency of pull phases(unit: second) + # Must be greater than digestWaitTime + responseWaitTime + pullInterval: 4s + # Number of peers to pull from + pullPeerNum: 3 + # Determines frequency of pulling state info messages from peers(unit: second) + requestStateInfoInterval: 4s + # Determines frequency of pushing state info messages to peers(unit: second) + publishStateInfoInterval: 4s + # Maximum time a stateInfo message is kept until expired + stateInfoRetentionInterval: + # Time from startup certificates are included in Alive messages(unit: second) + publishCertPeriod: 10s + # Should we skip verifying block messages or not (currently not in use) + skipBlockVerification: false + # Dial timeout(unit: second) + dialTimeout: 3s + # Connection timeout(unit: second) + connTimeout: 2s + # Buffer size of received messages + recvBuffSize: 20 + # Buffer size of sending messages + sendBuffSize: 200 + # Time to wait before pull engine processes incoming digests (unit: second) + # Should be slightly smaller than requestWaitTime + digestWaitTime: 1s + # Time to wait before pull engine removes incoming nonce (unit: milliseconds) + # Should be slightly bigger than digestWaitTime + requestWaitTime: 1500ms + # Time to wait before pull engine ends pull (unit: second) + responseWaitTime: 2s + # Alive check interval(unit: second) + aliveTimeInterval: 5s + # Alive expiration timeout(unit: second) + aliveExpirationTimeout: 25s + # Reconnect interval(unit: second) + reconnectInterval: 25s + # Max number of attempts to connect to a peer + maxConnectionAttempts: 120 + # Message expiration factor for alive messages + msgExpirationFactor: 20 + # This is an endpoint that is published to peers outside of the organization. + # If this isn't set, the peer will not be known to other organizations. + externalEndpoint: + # Leader election service configuration + election: + # Longest time peer waits for stable membership during leader election startup (unit: second) + startupGracePeriod: 15s + # Interval gossip membership samples to check its stability (unit: second) + membershipSampleInterval: 1s + # Time passes since last declaration message before peer decides to perform leader election (unit: second) + leaderAliveThreshold: 10s + # Time between peer sends propose message and declares itself as a leader (sends declaration message) (unit: second) + leaderElectionDuration: 5s + + pvtData: + # pullRetryThreshold determines the maximum duration of time private data corresponding for a given block + # would be attempted to be pulled from peers until the block would be committed without the private data + pullRetryThreshold: 60s + # As private data enters the transient store, it is associated with the peer's ledger's height at that time. + # transientstoreMaxBlockRetention defines the maximum difference between the current ledger's height upon commit, + # and the private data residing inside the transient store that is guaranteed not to be purged. + # Private data is purged from the transient store when blocks with sequences that are multiples + # of transientstoreMaxBlockRetention are committed. + transientstoreMaxBlockRetention: 1000 + # pushAckTimeout is the maximum time to wait for an acknowledgement from each peer + # at private data push at endorsement time. + pushAckTimeout: 3s + # Block to live pulling margin, used as a buffer + # to prevent peer from trying to pull private data + # from peers that is soon to be purged in next N blocks. + # This helps a newly joined peer catch up to current + # blockchain height quicker. + btlPullMargin: 10 + # the process of reconciliation is done in an endless loop, while in each iteration reconciler tries to + # pull from the other peers the most recent missing blocks with a maximum batch size limitation. + # reconcileBatchSize determines the maximum batch size of missing private data that will be reconciled in a + # single iteration. + reconcileBatchSize: 10 + # reconcileSleepInterval determines the time reconciler sleeps from end of an iteration until the beginning + # of the next reconciliation iteration. + reconcileSleepInterval: 1m + # reconciliationEnabled is a flag that indicates whether private data reconciliation is enable or not. + reconciliationEnabled: true + # skipPullingInvalidTransactionsDuringCommit is a flag that indicates whether pulling of invalid + # transaction's private data from other peers need to be skipped during the commit time and pulled + # only through reconciler. + skipPullingInvalidTransactionsDuringCommit: false + # implicitCollectionDisseminationPolicy specifies the dissemination policy for the peer's own implicit collection. + # When a peer endorses a proposal that writes to its own implicit collection, below values override the default values + # for disseminating private data. + # Note that it is applicable to all channels the peer has joined. The implication is that requiredPeerCount has to + # be smaller than the number of peers in a channel that has the lowest numbers of peers from the organization. + implicitCollectionDisseminationPolicy: + # requiredPeerCount defines the minimum number of eligible peers to which the peer must successfully + # disseminate private data for its own implicit collection during endorsement. Default value is 0. + requiredPeerCount: 0 + # maxPeerCount defines the maximum number of eligible peers to which the peer will attempt to + # disseminate private data for its own implicit collection during endorsement. Default value is 1. + maxPeerCount: 1 + + # Gossip state transfer related configuration + state: + # indicates whenever state transfer is enabled or not + # default value is true, i.e. state transfer is active + # and takes care to sync up missing blocks allowing + # lagging peer to catch up to speed with rest network. + # Keep in mind that when peer.gossip.useLeaderElection is true + # and there are several peers in the organization, + # or peer.gossip.useLeaderElection is false alongside with + # peer.gossip.orgleader being false, the peer's ledger may lag behind + # the rest of the peers and will never catch up due to state transfer + # being disabled. + enabled: false + # checkInterval interval to check whether peer is lagging behind enough to + # request blocks via state transfer from another peer. + checkInterval: 10s + # responseTimeout amount of time to wait for state transfer response from + # other peers + responseTimeout: 3s + # batchSize the number of blocks to request via state transfer from another peer + batchSize: 10 + # blockBufferSize reflects the size of the re-ordering buffer + # which captures blocks and takes care to deliver them in order + # down to the ledger layer. The actual buffer size is bounded between + # 0 and 2*blockBufferSize, each channel maintains its own buffer + blockBufferSize: 20 + # maxRetries maximum number of re-tries to ask + # for single state transfer request + maxRetries: 3 + + # TLS Settings + tls: + # Require server-side TLS + enabled: true + # Require client certificates / mutual TLS for inbound connections. + # Note that clients that are not configured to use a certificate will + # fail to connect to the peer. + clientAuthRequired: false + # X.509 certificate used for TLS server + cert: + file: tls/server.crt + # Private key used for TLS server + key: + file: tls/server.key + # rootcert.file represents the trusted root certificate chain used for verifying certificates + # of other nodes during outbound connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + rootcert: + file: tls/ca.crt + # If mutual TLS is enabled, clientRootCAs.files contains a list of additional root certificates + # used for verifying certificates of client connections. + # It augments the set of TLS CA certificates available from the MSPs of each channel’s configuration. + # Minimally, set your organization's TLS CA root certificate so that the peer can receive join channel requests. + clientRootCAs: + files: + - tls/ca.crt + # Private key used for TLS when making client connections. + # If not set, peer.tls.key.file will be used instead + clientKey: + file: + # X.509 certificate used for TLS when making client connections. + # If not set, peer.tls.cert.file will be used instead + clientCert: + file: + + # Authentication contains configuration parameters related to authenticating + # client messages + authentication: + # the acceptable difference between the current server time and the + # client's time as specified in a client request message + timewindow: 15m + + # Path on the file system where peer will store data (eg ledger). This + # location must be access control protected to prevent unintended + # modification that might corrupt the peer operations. + fileSystemPath: /var/hyperledger/production + + # BCCSP (Blockchain crypto provider): Select which crypto implementation or + # library to use + BCCSP: + Default: SW + # Settings for the SW crypto provider (i.e. when DEFAULT: SW) + SW: + # TODO: The default Hash and Security level needs refactoring to be + # fully configurable. Changing these defaults requires coordination + # SHA2 is hardcoded in several places, not only BCCSP + Hash: SHA2 + Security: 256 + # Location of Key Store + FileKeyStore: + # If "", defaults to 'mspConfigPath'/keystore + KeyStore: + # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) + PKCS11: + # Location of the PKCS11 module library + Library: + # Token Label + Label: + # User PIN + Pin: + Hash: + Security: + + # Path on the file system where peer will find MSP local configurations + mspConfigPath: msp + + # Identifier of the local MSP + # ----!!!!IMPORTANT!!!-!!!IMPORTANT!!!-!!!IMPORTANT!!!!---- + # Deployers need to change the value of the localMspId string. + # In particular, the name of the local MSP ID of a peer needs + # to match the name of one of the MSPs in each of the channel + # that this peer is a member of. Otherwise this peer's messages + # will not be identified as valid by other nodes. + localMspId: Org1MSP + + # CLI common client config options + client: + # connection timeout + connTimeout: 3s + + # Delivery service related config + deliveryclient: + # It sets the total time the delivery service may spend in reconnection + # attempts until its retry logic gives up and returns an error + reconnectTotalTimeThreshold: 3600s + + # It sets the delivery service <-> ordering service node connection timeout + connTimeout: 3s + + # It sets the delivery service maximal delay between consecutive retries + reConnectBackoffThreshold: 3600s + + # A list of orderer endpoint addresses which should be overridden + # when found in channel configurations. + addressOverrides: + # - from: + # to: + # caCertsFile: + # - from: + # to: + # caCertsFile: + + # Type for the local MSP - by default it's of type bccsp + localMspType: bccsp + + # Used with Go profiling tools only in none production environment. In + # production, it should be disabled (eg enabled: false) + profile: + enabled: false + listenAddress: 0.0.0.0:6060 + + # Handlers defines custom handlers that can filter and mutate + # objects passing within the peer, such as: + # Auth filter - reject or forward proposals from clients + # Decorators - append or mutate the chaincode input passed to the chaincode + # Endorsers - Custom signing over proposal response payload and its mutation + # Valid handler definition contains: + # - A name which is a factory method name defined in + # core/handlers/library/library.go for statically compiled handlers + # - library path to shared object binary for pluggable filters + # Auth filters and decorators are chained and executed in the order that + # they are defined. For example: + # authFilters: + # - + # name: FilterOne + # library: /opt/lib/filter.so + # - + # name: FilterTwo + # decorators: + # - + # name: DecoratorOne + # - + # name: DecoratorTwo + # library: /opt/lib/decorator.so + # Endorsers are configured as a map that its keys are the endorsement system chaincodes that are being overridden. + # Below is an example that overrides the default ESCC and uses an endorsement plugin that has the same functionality + # as the default ESCC. + # If the 'library' property is missing, the name is used as the constructor method in the builtin library similar + # to auth filters and decorators. + # endorsers: + # escc: + # name: DefaultESCC + # library: /etc/hyperledger/fabric/plugin/escc.so + handlers: + authFilters: + - + name: DefaultAuth + - + name: ExpirationCheck # This filter checks identity x509 certificate expiration + decorators: + - + name: DefaultDecorator + endorsers: + escc: + name: DefaultEndorsement + library: + validators: + vscc: + name: DefaultValidation + library: + + # library: /etc/hyperledger/fabric/plugin/escc.so + # Number of goroutines that will execute transaction validation in parallel. + # By default, the peer chooses the number of CPUs on the machine. Set this + # variable to override that choice. + # NOTE: overriding this value might negatively influence the performance of + # the peer so please change this value only if you know what you're doing + validatorPoolSize: + + # The discovery service is used by clients to query information about peers, + # such as - which peers have joined a certain channel, what is the latest + # channel config, and most importantly - given a chaincode and a channel, + # what possible sets of peers satisfy the endorsement policy. + discovery: + enabled: true + # Whether the authentication cache is enabled or not. + authCacheEnabled: true + # The maximum size of the cache, after which a purge takes place + authCacheMaxSize: 1000 + # The proportion (0 to 1) of entries that remain in the cache after the cache is purged due to overpopulation + authCachePurgeRetentionRatio: 0.75 + # Whether to allow non-admins to perform non channel scoped queries. + # When this is false, it means that only peer admins can perform non channel scoped queries. + orgMembersAllowedAccess: false + + # Limits is used to configure some internal resource limits. + limits: + # Concurrency limits the number of concurrently running requests to a service on each peer. + # Currently this option is only applied to endorser service and deliver service. + # When the property is missing or the value is 0, the concurrency limit is disabled for the service. + concurrency: + # endorserService limits concurrent requests to endorser service that handles chaincode deployment, query and invocation, + # including both user chaincodes and system chaincodes. + endorserService: 2500 + # deliverService limits concurrent event listeners registered to deliver service for blocks and transaction events. + deliverService: 2500 + +############################################################################### +# +# VM section +# +############################################################################### +vm: + + # Endpoint of the vm management system. For docker can be one of the following in general + # unix:///var/run/docker.sock + # http://localhost:2375 + # https://localhost:2376 + endpoint: unix:///var/run/docker.sock + + # settings for docker vms + docker: + tls: + enabled: false + ca: + file: docker/ca.crt + cert: + file: docker/tls.crt + key: + file: docker/tls.key + + # Enables/disables the standard out/err from chaincode containers for + # debugging purposes + attachStdout: false + + # Parameters on creating docker container. + # Container may be efficiently created using ipam & dns-server for cluster + # NetworkMode - sets the networking mode for the container. Supported + # standard values are: `host`(default),`bridge`,`ipvlan`,`none`. + # Dns - a list of DNS servers for the container to use. + # Note: `Privileged` `Binds` `Links` and `PortBindings` properties of + # Docker Host Config are not supported and will not be used if set. + # LogConfig - sets the logging driver (Type) and related options + # (Config) for Docker. For more info, + # https://docs.docker.com/engine/admin/logging/overview/ + # Note: Set LogConfig using Environment Variables is not supported. + hostConfig: + NetworkMode: host + Dns: + # - 192.168.0.1 + LogConfig: + Type: json-file + Config: + max-size: "50m" + max-file: "5" + Memory: 2147483648 + +############################################################################### +# +# Chaincode section +# +############################################################################### +chaincode: + + # The id is used by the Chaincode stub to register the executing Chaincode + # ID with the Peer and is generally supplied through ENV variables + # the `path` form of ID is provided when installing the chaincode. + # The `name` is used for all other requests and can be any string. + id: + path: + name: + + # Generic builder environment, suitable for most chaincode types + builder: $(DOCKER_NS)/fabric-ccenv:$(TWO_DIGIT_VERSION) + + # Enables/disables force pulling of the base docker images (listed below) + # during user chaincode instantiation. + # Useful when using moving image tags (such as :latest) + pull: false + + golang: + # golang will never need more than baseos + runtime: $(DOCKER_NS)/fabric-baseos:$(TWO_DIGIT_VERSION) + + # whether or not golang chaincode should be linked dynamically + dynamicLink: false + + java: + # This is an image based on java:openjdk-8 with addition compiler + # tools added for java shim layer packaging. + # This image is packed with shim layer libraries that are necessary + # for Java chaincode runtime. + runtime: $(DOCKER_NS)/fabric-javaenv:$(TWO_DIGIT_VERSION) + + node: + # This is an image based on node:$(NODE_VER)-alpine + runtime: $(DOCKER_NS)/fabric-nodeenv:$(TWO_DIGIT_VERSION) + + # 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: + - path: /var/hyperledger/fabric/chaincode/ccs-builder + name: ccs-builder + propagateEnvironment: + - HOME + - CORE_PEER_ID + - CORE_PEER_LOCALMSPID + + # The maximum duration to wait for the chaincode build and install process + # to complete. + installTimeout: 300s + + # Timeout duration for starting up a container and waiting for Register + # to come through. + startuptimeout: 300s + + # Timeout duration for Invoke and Init calls to prevent runaway. + # This timeout is used by all chaincodes in all the channels, including + # system chaincodes. + # Note that during Invoke, if the image is not available (e.g. being + # cleaned up when in development environment), the peer will automatically + # build the image, which might take more time. In production environment, + # the chaincode image is unlikely to be deleted, so the timeout could be + # reduced accordingly. + executetimeout: 30s + + # There are 2 modes: "dev" and "net". + # In dev mode, user runs the chaincode after starting peer from + # command line on local machine. + # In net mode, peer will run chaincode in a docker container. + mode: net + + # keepalive in seconds. In situations where the communication goes through a + # proxy that does not support keep-alive, this parameter will maintain connection + # between peer and chaincode. + # A value <= 0 turns keepalive off + keepalive: 0 + + # enabled system chaincodes + system: + _lifecycle: enable + cscc: enable + lscc: enable + qscc: enable + + # Logging section for the chaincode container + logging: + # Default level for all loggers within the chaincode container + level: info + # Override default level for the 'shim' logger + shim: warning + # Format for the chaincode container logs + format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}' + +############################################################################### +# +# Ledger section - ledger configuration encompasses both the blockchain +# and the state +# +############################################################################### +ledger: + + blockchain: + + state: + # stateDatabase - options are "goleveldb", "CouchDB" + # goleveldb - default state database stored in goleveldb. + # CouchDB - store state database in CouchDB + stateDatabase: goleveldb + # Limit on the number of records to return per query + totalQueryLimit: 100000 + couchDBConfig: + # It is recommended to run CouchDB on the same server as the peer, and + # not map the CouchDB container port to a server port in docker-compose. + # Otherwise proper security must be provided on the connection between + # CouchDB client (on the peer) and server. + couchDBAddress: 127.0.0.1:5984 + # This username must have read and write authority on CouchDB + username: + # The password is recommended to pass as an environment variable + # during start up (eg CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD). + # If it is stored here, the file must be access control protected + # to prevent unintended users from discovering the password. + password: + # Number of retries for CouchDB errors + maxRetries: 3 + # Number of retries for CouchDB errors during peer startup. + # The delay between retries doubles for each attempt. + # Default of 10 retries results in 11 attempts over 2 minutes. + maxRetriesOnStartup: 10 + # CouchDB request timeout (unit: duration, e.g. 20s) + requestTimeout: 35s + # Limit on the number of records per each CouchDB query + # Note that chaincode queries are only bound by totalQueryLimit. + # Internally the chaincode may execute multiple CouchDB queries, + # each of size internalQueryLimit. + internalQueryLimit: 1000 + # Limit on the number of records per CouchDB bulk update batch + maxBatchUpdateSize: 1000 + # Warm indexes after every N blocks. + # This option warms any indexes that have been + # deployed to CouchDB after every N blocks. + # A value of 1 will warm indexes after every block commit, + # to ensure fast selector queries. + # Increasing the value may improve write efficiency of peer and CouchDB, + # but may degrade query response time. + warmIndexesAfterNBlocks: 1 + # Create the _global_changes system database + # This is optional. Creating the global changes database will require + # additional system resources to track changes and maintain the database + createGlobalChangesDB: false + # CacheSize denotes the maximum mega bytes (MB) to be allocated for the in-memory state + # cache. Note that CacheSize needs to be a multiple of 32 MB. If it is not a multiple + # of 32 MB, the peer would round the size to the next multiple of 32 MB. + # To disable the cache, 0 MB needs to be assigned to the cacheSize. + cacheSize: 64 + + history: + # enableHistoryDatabase - options are true or false + # Indicates if the history of key updates should be stored. + # All history 'index' will be stored in goleveldb, regardless if using + # CouchDB or alternate database for the state. + enableHistoryDatabase: true + + pvtdataStore: + # the maximum db batch size for converting + # the ineligible missing data entries to eligible missing data entries + collElgProcMaxDbBatchSize: 5000 + # the minimum duration (in milliseconds) between writing + # two consecutive db batches for converting the ineligible missing data entries to eligible missing data entries + collElgProcDbBatchesInterval: 1000 + # The missing data entries are classified into two categories: + # (1) prioritized + # (2) deprioritized + # Initially, all missing data are in the prioritized list. When the + # reconciler is unable to fetch the missing data from other peers, + # the unreconciled missing data would be moved to the deprioritized list. + # The reconciler would retry deprioritized missing data after every + # deprioritizedDataReconcilerInterval (unit: minutes). Note that the + # interval needs to be greater than the reconcileSleepInterval + deprioritizedDataReconcilerInterval: 60m + + snapshots: + # Path on the file system where peer will store ledger snapshots + rootDir: /var/hyperledger/production/snapshots + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9443 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # most operations service endpoints require client authentication when TLS + # is enabled. clientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # metrics provider is one of statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd metrics + prefix: diff --git a/test-network-k8s/config/org1/fabric-ecert-ca-server-config.yaml b/test-network-k8s/config/org1/fabric-ecert-ca-server-config.yaml new file mode 100644 index 00000000..f1ed9da4 --- /dev/null +++ b/test-network-k8s/config/org1/fabric-ecert-ca-server-config.yaml @@ -0,0 +1,506 @@ +############################################################################# +# This is a configuration file for the fabric-ca-server command. +# +# COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES +# ------------------------------------------------ +# Each configuration element can be overridden via command line +# arguments or environment variables. The precedence for determining +# the value of each element is as follows: +# 1) command line argument +# Examples: +# a) --port 443 +# To set the listening port +# b) --ca.keyfile ../mykey.pem +# To set the "keyfile" element in the "ca" section below; +# note the '.' separator character. +# 2) environment variable +# Examples: +# a) FABRIC_CA_SERVER_PORT=443 +# To set the listening port +# b) FABRIC_CA_SERVER_CA_KEYFILE="../mykey.pem" +# To set the "keyfile" element in the "ca" section below; +# note the '_' separator character. +# 3) configuration file +# 4) default value (if there is one) +# All default values are shown beside each element below. +# +# FILE NAME ELEMENTS +# ------------------ +# The value of all fields whose name ends with "file" or "files" are +# name or names of other files. +# For example, see "tls.certfile" and "tls.clientauth.certfiles". +# The value of each of these fields can be a simple filename, a +# relative path, or an absolute path. If the value is not an +# absolute path, it is interpretted as being relative to the location +# of this configuration file. +# +############################################################################# + +# Version of config file +version: 1.5.2 + +# Server's listening port (default: 7054) +port: 443 + +# Cross-Origin Resource Sharing (CORS) +cors: + enabled: false + origins: + - "*" + +# Enables debug logging (default: false) +debug: false + +# Size limit of an acceptable CRL in bytes (default: 512000) +crlsizelimit: 512000 + +############################################################################# +# TLS section for the server's listening port +# +# The following types are supported for client authentication: NoClientCert, +# RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, +# and RequireAndVerifyClientCert. +# +# Certfiles is a list of root certificate authorities that the server uses +# when verifying client certificates. +############################################################################# +tls: + # Enable TLS (default: false) + enabled: true + # TLS for the server's listening port + certfile: + keyfile: + clientauth: + type: noclientcert + certfiles: + +############################################################################# +# The CA section contains information related to the Certificate Authority +# including the name of the CA, which should be unique for all members +# of a blockchain network. It also includes the key and certificate files +# used when issuing enrollment certificates (ECerts) and transaction +# certificates (TCerts). +# The chainfile (if it exists) contains the certificate chain which +# should be trusted for this CA, where the 1st in the chain is always the +# root CA certificate. +############################################################################# +ca: + # Name of this CA + name: org1-ecert-ca + # Key file (is only used to import a private key into BCCSP) + keyfile: + # Certificate file (default: ca-cert.pem) + certfile: + # Chain file + chainfile: + +############################################################################# +# The gencrl REST endpoint is used to generate a CRL that contains revoked +# certificates. This section contains configuration options that are used +# during gencrl request processing. +############################################################################# +crl: + # Specifies expiration for the generated CRL. The number of hours + # specified by this property is added to the UTC time, the resulting time + # is used to set the 'Next Update' date of the CRL. + expiry: 24h + +############################################################################# +# The registry section controls how the fabric-ca-server does two things: +# 1) authenticates enrollment requests which contain a username and password +# (also known as an enrollment ID and secret). +# 2) once authenticated, retrieves the identity's attribute names and +# values which the fabric-ca-server optionally puts into TCerts +# which it issues for transacting on the Hyperledger Fabric blockchain. +# These attributes are useful for making access control decisions in +# chaincode. +# There are two main configuration options: +# 1) The fabric-ca-server is the registry. +# This is true if "ldap.enabled" in the ldap section below is false. +# 2) An LDAP server is the registry, in which case the fabric-ca-server +# calls the LDAP server to perform these tasks. +# This is true if "ldap.enabled" in the ldap section below is true, +# which means this "registry" section is ignored. +############################################################################# +registry: + # Maximum number of times a password/secret can be reused for enrollment + # (default: -1, which means there is no limit) + maxenrollments: -1 + + # Contains identity information which is used when LDAP is disabled + identities: + - name: rcaadmin + pass: rcaadminpw + type: client + affiliation: "" + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + +############################################################################# +# Database section +# Supported types are: "sqlite3", "postgres", and "mysql". +# The datasource value depends on the type. +# If the type is "sqlite3", the datasource value is a file name to use +# as the database store. Since "sqlite3" is an embedded database, it +# may not be used if you want to run the fabric-ca-server in a cluster. +# To run the fabric-ca-server in a cluster, you must choose "postgres" +# or "mysql". +############################################################################# +db: + type: sqlite3 + datasource: fabric-ca-server.db + tls: + enabled: false + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# LDAP section +# If LDAP is enabled, the fabric-ca-server calls LDAP to: +# 1) authenticate enrollment ID and secret (i.e. username and password) +# for enrollment requests; +# 2) To retrieve identity attributes +############################################################################# +ldap: + # Enables or disables the LDAP client (default: false) + # If this is set to true, the "registry" section is ignored. + enabled: false + # The URL of the LDAP server + url: ldap://:@:/ + # TLS configuration for the client connection to the LDAP server + tls: + certfiles: + client: + certfile: + keyfile: + # Attribute related configuration for mapping from LDAP entries to Fabric CA attributes + attribute: + # 'names' is an array of strings containing the LDAP attribute names which are + # requested from the LDAP server for an LDAP identity's entry + names: ['uid','member'] + # The 'converters' section is used to convert an LDAP entry to the value of + # a fabric CA attribute. + # For example, the following converts an LDAP 'uid' attribute + # whose value begins with 'revoker' to a fabric CA attribute + # named "hf.Revoker" with a value of "true" (because the boolean expression + # evaluates to true). + # converters: + # - name: hf.Revoker + # value: attr("uid") =~ "revoker*" + converters: + - name: + value: + # The 'maps' section contains named maps which may be referenced by the 'map' + # function in the 'converters' section to map LDAP responses to arbitrary values. + # For example, assume a user has an LDAP attribute named 'member' which has multiple + # values which are each a distinguished name (i.e. a DN). For simplicity, assume the + # values of the 'member' attribute are 'dn1', 'dn2', and 'dn3'. + # Further assume the following configuration. + # converters: + # - name: hf.Registrar.Roles + # value: map(attr("member"),"groups") + # maps: + # groups: + # - name: dn1 + # value: peer + # - name: dn2 + # value: client + # The value of the user's 'hf.Registrar.Roles' attribute is then computed to be + # "peer,client,dn3". This is because the value of 'attr("member")' is + # "dn1,dn2,dn3", and the call to 'map' with a 2nd argument of + # "group" replaces "dn1" with "peer" and "dn2" with "client". + maps: + groups: + - name: + value: + +############################################################################# +# Affiliations section. Fabric CA server can be bootstrapped with the +# affiliations specified in this section. Affiliations are specified as maps. +# For example: +# businessunit1: +# department1: +# - team1 +# businessunit2: +# - department2 +# - department3 +# +# Affiliations are hierarchical in nature. In the above example, +# department1 (used as businessunit1.department1) is the child of businessunit1. +# team1 (used as businessunit1.department1.team1) is the child of department1. +# department2 (used as businessunit2.department2) and department3 (businessunit2.department3) +# are children of businessunit2. +# Note: Affiliations are case sensitive except for the non-leaf affiliations +# (like businessunit1, department1, businessunit2) that are specified in the configuration file, +# which are always stored in lower case. +############################################################################# +affiliations: + org1: + - department1 + - department2 + org2: + - department1 + +############################################################################# +# Signing section +# +# The "default" subsection is used to sign enrollment certificates; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +# +# The "ca" profile subsection is used to sign intermediate CA certificates; +# the default expiration ("expiry" field) is "43800h" which is 5 years in hours. +# Note that "isca" is true, meaning that it issues a CA certificate. +# A maxpathlen of 0 means that the intermediate CA cannot issue other +# intermediate CA certificates, though it can still issue end entity certificates. +# (See RFC 5280, section 4.2.1.9) +# +# The "tls" profile subsection is used to sign TLS certificate requests; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +############################################################################# +signing: + default: + usage: + - digital signature + expiry: 8760h + profiles: + ca: + usage: + - cert sign + - crl sign + expiry: 43800h + caconstraint: + isca: true + maxpathlen: 0 + tls: + usage: + - signing + - key encipherment + - server auth + - client auth + - key agreement + expiry: 8760h + +########################################################################### +# Certificate Signing Request (CSR) section. +# This controls the creation of the root CA certificate. +# The expiration for the root CA certificate is configured with the +# "ca.expiry" field below, whose default value is "131400h" which is +# 15 years in hours. +# The pathlength field is used to limit CA certificate hierarchy as described +# in section 4.2.1.9 of RFC 5280. +# Examples: +# 1) No pathlength value means no limit is requested. +# 2) pathlength == 1 means a limit of 1 is requested which is the default for +# a root CA. This means the root CA can issue intermediate CA certificates, +# but these intermediate CAs may not in turn issue other CA certificates +# though they can still issue end entity certificates. +# 3) pathlength == 0 means a limit of 0 is requested; +# this is the default for an intermediate CA, which means it can not issue +# CA certificates though it can still issue end entity certificates. +########################################################################### +csr: + cn: fabric-ca-server + keyrequest: + algo: ecdsa + size: 256 + names: + - C: US + ST: "North Carolina" + L: + O: Hyperledger + OU: Fabric + hosts: + - localhost + - 127.0.0.1 + - org1-ecert-ca + - org1-ecert-ca.test-network.svc.cluster.local + ca: + expiry: 131400h + pathlength: 1 + +########################################################################### +# Each CA can issue both X509 enrollment certificate as well as Idemix +# Credential. This section specifies configuration for the issuer component +# that is responsible for issuing Idemix credentials. +########################################################################### +idemix: + # Specifies pool size for revocation handles. A revocation handle is an unique identifier of an + # Idemix credential. The issuer will create a pool revocation handles of this specified size. When + # a credential is requested, issuer will get handle from the pool and assign it to the credential. + # Issuer will repopulate the pool with new handles when the last handle in the pool is used. + # A revocation handle and credential revocation information (CRI) are used to create non revocation proof + # by the prover to prove to the verifier that her credential is not revoked. + rhpoolsize: 1000 + + # The Idemix credential issuance is a two step process. First step is to get a nonce from the issuer + # and second step is send credential request that is constructed using the nonce to the isuser to + # request a credential. This configuration property specifies expiration for the nonces. By default is + # nonces expire after 15 seconds. The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration). + nonceexpiration: 15s + + # Specifies interval at which expired nonces are removed from datastore. Default value is 15 minutes. + # The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration) + noncesweepinterval: 15m + +############################################################################# +# BCCSP (BlockChain Crypto Service Provider) section is used to select which +# crypto library implementation to use +############################################################################# +bccsp: + default: SW + sw: + hash: SHA2 + security: 256 + filekeystore: + # The directory used for the software file-based keystore + keystore: msp/keystore + +############################################################################# +# Multi CA section +# +# Each Fabric CA server contains one CA by default. This section is used +# to configure multiple CAs in a single server. +# +# 1) --cacount +# Automatically generate non-default CAs. The names of these +# additional CAs are "ca1", "ca2", ... "caN", where "N" is +# This is particularly useful in a development environment to quickly set up +# multiple CAs. Note that, this config option is not applicable to intermediate CA server +# i.e., Fabric CA server that is started with intermediate.parentserver.url config +# option (-u command line option) +# +# 2) --cafiles +# For each CA config file in the list, generate a separate signing CA. Each CA +# config file in this list MAY contain all of the same elements as are found in +# the server config file except port, debug, and tls sections. +# +# Examples: +# fabric-ca-server start -b admin:adminpw --cacount 2 +# +# fabric-ca-server start -b admin:adminpw --cafiles ca/ca1/fabric-ca-server-config.yaml +# --cafiles ca/ca2/fabric-ca-server-config.yaml +# +############################################################################# + +cacount: + +cafiles: + +############################################################################# +# Intermediate CA section +# +# The relationship between servers and CAs is as follows: +# 1) A single server process may contain or function as one or more CAs. +# This is configured by the "Multi CA section" above. +# 2) Each CA is either a root CA or an intermediate CA. +# 3) Each intermediate CA has a parent CA which is either a root CA or another intermediate CA. +# +# This section pertains to configuration of #2 and #3. +# If the "intermediate.parentserver.url" property is set, +# then this is an intermediate CA with the specified parent +# CA. +# +# parentserver section +# url - The URL of the parent server +# caname - Name of the CA to enroll within the server +# +# enrollment section used to enroll intermediate CA with parent CA +# profile - Name of the signing profile to use in issuing the certificate +# label - Label to use in HSM operations +# +# tls section for secure socket connection +# certfiles - PEM-encoded list of trusted root certificate files +# client: +# certfile - PEM-encoded certificate file for when client authentication +# is enabled on server +# keyfile - PEM-encoded key file for when client authentication +# is enabled on server +############################################################################# +intermediate: + parentserver: + url: + caname: + + enrollment: + hosts: + profile: + label: + + tls: + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# CA configuration section +# +# Configure the number of incorrect password attempts are allowed for +# identities. By default, the value of 'passwordattempts' is 10, which +# means that 10 incorrect password attempts can be made before an identity get +# locked out. +############################################################################# +cfg: + identities: + passwordattempts: 10 + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9443 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # require client certificate authentication to access all resources + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushsed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd merics + prefix: server diff --git a/test-network-k8s/config/org1/fabric-tls-ca-server-config.yaml b/test-network-k8s/config/org1/fabric-tls-ca-server-config.yaml new file mode 100644 index 00000000..23860537 --- /dev/null +++ b/test-network-k8s/config/org1/fabric-tls-ca-server-config.yaml @@ -0,0 +1,496 @@ +############################################################################# +# This is a configuration file for the fabric-ca-server command. +# +# COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES +# ------------------------------------------------ +# Each configuration element can be overridden via command line +# arguments or environment variables. The precedence for determining +# the value of each element is as follows: +# 1) command line argument +# Examples: +# a) --port 443 +# To set the listening port +# b) --ca.keyfile ../mykey.pem +# To set the "keyfile" element in the "ca" section below; +# note the '.' separator character. +# 2) environment variable +# Examples: +# a) FABRIC_CA_SERVER_PORT=443 +# To set the listening port +# b) FABRIC_CA_SERVER_CA_KEYFILE="../mykey.pem" +# To set the "keyfile" element in the "ca" section below; +# note the '_' separator character. +# 3) configuration file +# 4) default value (if there is one) +# All default values are shown beside each element below. +# +# FILE NAME ELEMENTS +# ------------------ +# The value of all fields whose name ends with "file" or "files" are +# name or names of other files. +# For example, see "tls.certfile" and "tls.clientauth.certfiles". +# The value of each of these fields can be a simple filename, a +# relative path, or an absolute path. If the value is not an +# absolute path, it is interpretted as being relative to the location +# of this configuration file. +# +############################################################################# + +# Version of config file +version: 1.5.2 + +# Server's listening port (default: 7054) +port: 443 + +# Cross-Origin Resource Sharing (CORS) +cors: + enabled: false + origins: + - "*" + +# Enables debug logging (default: false) +debug: false + +# Size limit of an acceptable CRL in bytes (default: 512000) +crlsizelimit: 512000 + +############################################################################# +# TLS section for the server's listening port +# +# The following types are supported for client authentication: NoClientCert, +# RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, +# and RequireAndVerifyClientCert. +# +# Certfiles is a list of root certificate authorities that the server uses +# when verifying client certificates. +############################################################################# +tls: + # Enable TLS (default: false) + enabled: true + # TLS for the server's listening port + certfile: + keyfile: + clientauth: + type: noclientcert + certfiles: + +############################################################################# +# The CA section contains information related to the Certificate Authority +# including the name of the CA, which should be unique for all members +# of a blockchain network. It also includes the key and certificate files +# used when issuing enrollment certificates (ECerts) and transaction +# certificates (TCerts). +# The chainfile (if it exists) contains the certificate chain which +# should be trusted for this CA, where the 1st in the chain is always the +# root CA certificate. +############################################################################# +ca: + # Name of this CA + name: org1-tls-ca + # Key file (is only used to import a private key into BCCSP) + keyfile: + # Certificate file (default: ca-cert.pem) + certfile: + # Chain file + chainfile: + +############################################################################# +# The gencrl REST endpoint is used to generate a CRL that contains revoked +# certificates. This section contains configuration options that are used +# during gencrl request processing. +############################################################################# +crl: + # Specifies expiration for the generated CRL. The number of hours + # specified by this property is added to the UTC time, the resulting time + # is used to set the 'Next Update' date of the CRL. + expiry: 24h + +############################################################################# +# The registry section controls how the fabric-ca-server does two things: +# 1) authenticates enrollment requests which contain a username and password +# (also known as an enrollment ID and secret). +# 2) once authenticated, retrieves the identity's attribute names and +# values which the fabric-ca-server optionally puts into TCerts +# which it issues for transacting on the Hyperledger Fabric blockchain. +# These attributes are useful for making access control decisions in +# chaincode. +# There are two main configuration options: +# 1) The fabric-ca-server is the registry. +# This is true if "ldap.enabled" in the ldap section below is false. +# 2) An LDAP server is the registry, in which case the fabric-ca-server +# calls the LDAP server to perform these tasks. +# This is true if "ldap.enabled" in the ldap section below is true, +# which means this "registry" section is ignored. +############################################################################# +registry: + # Maximum number of times a password/secret can be reused for enrollment + # (default: -1, which means there is no limit) + maxenrollments: -1 + + # Contains identity information which is used when LDAP is disabled + identities: + - name: tlsadmin + pass: tlsadminpw + type: client + affiliation: "" + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + +############################################################################# +# Database section +# Supported types are: "sqlite3", "postgres", and "mysql". +# The datasource value depends on the type. +# If the type is "sqlite3", the datasource value is a file name to use +# as the database store. Since "sqlite3" is an embedded database, it +# may not be used if you want to run the fabric-ca-server in a cluster. +# To run the fabric-ca-server in a cluster, you must choose "postgres" +# or "mysql". +############################################################################# +db: + type: sqlite3 + datasource: fabric-ca-server.db + tls: + enabled: false + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# LDAP section +# If LDAP is enabled, the fabric-ca-server calls LDAP to: +# 1) authenticate enrollment ID and secret (i.e. username and password) +# for enrollment requests; +# 2) To retrieve identity attributes +############################################################################# +ldap: + # Enables or disables the LDAP client (default: false) + # If this is set to true, the "registry" section is ignored. + enabled: false + # The URL of the LDAP server + url: ldap://:@:/ + # TLS configuration for the client connection to the LDAP server + tls: + certfiles: + client: + certfile: + keyfile: + # Attribute related configuration for mapping from LDAP entries to Fabric CA attributes + attribute: + # 'names' is an array of strings containing the LDAP attribute names which are + # requested from the LDAP server for an LDAP identity's entry + names: ['uid','member'] + # The 'converters' section is used to convert an LDAP entry to the value of + # a fabric CA attribute. + # For example, the following converts an LDAP 'uid' attribute + # whose value begins with 'revoker' to a fabric CA attribute + # named "hf.Revoker" with a value of "true" (because the boolean expression + # evaluates to true). + # converters: + # - name: hf.Revoker + # value: attr("uid") =~ "revoker*" + converters: + - name: + value: + # The 'maps' section contains named maps which may be referenced by the 'map' + # function in the 'converters' section to map LDAP responses to arbitrary values. + # For example, assume a user has an LDAP attribute named 'member' which has multiple + # values which are each a distinguished name (i.e. a DN). For simplicity, assume the + # values of the 'member' attribute are 'dn1', 'dn2', and 'dn3'. + # Further assume the following configuration. + # converters: + # - name: hf.Registrar.Roles + # value: map(attr("member"),"groups") + # maps: + # groups: + # - name: dn1 + # value: peer + # - name: dn2 + # value: client + # The value of the user's 'hf.Registrar.Roles' attribute is then computed to be + # "peer,client,dn3". This is because the value of 'attr("member")' is + # "dn1,dn2,dn3", and the call to 'map' with a 2nd argument of + # "group" replaces "dn1" with "peer" and "dn2" with "client". + maps: + groups: + - name: + value: + +############################################################################# +# Affiliations section. Fabric CA server can be bootstrapped with the +# affiliations specified in this section. Affiliations are specified as maps. +# For example: +# businessunit1: +# department1: +# - team1 +# businessunit2: +# - department2 +# - department3 +# +# Affiliations are hierarchical in nature. In the above example, +# department1 (used as businessunit1.department1) is the child of businessunit1. +# team1 (used as businessunit1.department1.team1) is the child of department1. +# department2 (used as businessunit2.department2) and department3 (businessunit2.department3) +# are children of businessunit2. +# Note: Affiliations are case sensitive except for the non-leaf affiliations +# (like businessunit1, department1, businessunit2) that are specified in the configuration file, +# which are always stored in lower case. +############################################################################# +affiliations: + org1: + - department1 + - department2 + org2: + - department1 + +############################################################################# +# Signing section +# +# The "default" subsection is used to sign enrollment certificates; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +# +# The "ca" profile subsection is used to sign intermediate CA certificates; +# the default expiration ("expiry" field) is "43800h" which is 5 years in hours. +# Note that "isca" is true, meaning that it issues a CA certificate. +# A maxpathlen of 0 means that the intermediate CA cannot issue other +# intermediate CA certificates, though it can still issue end entity certificates. +# (See RFC 5280, section 4.2.1.9) +# +# The "tls" profile subsection is used to sign TLS certificate requests; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +############################################################################# +signing: + default: + authremote: {} + caconstraint: {} + expiry: 8760h + usage: + - signing + - key encipherment + - server auth + - client auth + - key agreement + profiles: null + +########################################################################### +# Certificate Signing Request (CSR) section. +# This controls the creation of the root CA certificate. +# The expiration for the root CA certificate is configured with the +# "ca.expiry" field below, whose default value is "131400h" which is +# 15 years in hours. +# The pathlength field is used to limit CA certificate hierarchy as described +# in section 4.2.1.9 of RFC 5280. +# Examples: +# 1) No pathlength value means no limit is requested. +# 2) pathlength == 1 means a limit of 1 is requested which is the default for +# a root CA. This means the root CA can issue intermediate CA certificates, +# but these intermediate CAs may not in turn issue other CA certificates +# though they can still issue end entity certificates. +# 3) pathlength == 0 means a limit of 0 is requested; +# this is the default for an intermediate CA, which means it can not issue +# CA certificates though it can still issue end entity certificates. +########################################################################### +csr: + cn: fabric-ca-server + keyrequest: + algo: ecdsa + size: 256 + names: + - C: US + ST: "North Carolina" + L: + O: Hyperledger + OU: Fabric + hosts: + - localhost + - 127.0.0.1 + - org1-tls-ca + - org1-tls-ca.test-network.svc.cluster.local + ca: + expiry: 131400h + pathlength: 1 + +########################################################################### +# Each CA can issue both X509 enrollment certificate as well as Idemix +# Credential. This section specifies configuration for the issuer component +# that is responsible for issuing Idemix credentials. +########################################################################### +idemix: + # Specifies pool size for revocation handles. A revocation handle is an unique identifier of an + # Idemix credential. The issuer will create a pool revocation handles of this specified size. When + # a credential is requested, issuer will get handle from the pool and assign it to the credential. + # Issuer will repopulate the pool with new handles when the last handle in the pool is used. + # A revocation handle and credential revocation information (CRI) are used to create non revocation proof + # by the prover to prove to the verifier that her credential is not revoked. + rhpoolsize: 1000 + + # The Idemix credential issuance is a two step process. First step is to get a nonce from the issuer + # and second step is send credential request that is constructed using the nonce to the isuser to + # request a credential. This configuration property specifies expiration for the nonces. By default is + # nonces expire after 15 seconds. The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration). + nonceexpiration: 15s + + # Specifies interval at which expired nonces are removed from datastore. Default value is 15 minutes. + # The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration) + noncesweepinterval: 15m + +############################################################################# +# BCCSP (BlockChain Crypto Service Provider) section is used to select which +# crypto library implementation to use +############################################################################# +bccsp: + default: SW + sw: + hash: SHA2 + security: 256 + filekeystore: + # The directory used for the software file-based keystore + keystore: msp/keystore + +############################################################################# +# Multi CA section +# +# Each Fabric CA server contains one CA by default. This section is used +# to configure multiple CAs in a single server. +# +# 1) --cacount +# Automatically generate non-default CAs. The names of these +# additional CAs are "ca1", "ca2", ... "caN", where "N" is +# This is particularly useful in a development environment to quickly set up +# multiple CAs. Note that, this config option is not applicable to intermediate CA server +# i.e., Fabric CA server that is started with intermediate.parentserver.url config +# option (-u command line option) +# +# 2) --cafiles +# For each CA config file in the list, generate a separate signing CA. Each CA +# config file in this list MAY contain all of the same elements as are found in +# the server config file except port, debug, and tls sections. +# +# Examples: +# fabric-ca-server start -b admin:adminpw --cacount 2 +# +# fabric-ca-server start -b admin:adminpw --cafiles ca/ca1/fabric-ca-server-config.yaml +# --cafiles ca/ca2/fabric-ca-server-config.yaml +# +############################################################################# + +cacount: + +cafiles: + +############################################################################# +# Intermediate CA section +# +# The relationship between servers and CAs is as follows: +# 1) A single server process may contain or function as one or more CAs. +# This is configured by the "Multi CA section" above. +# 2) Each CA is either a root CA or an intermediate CA. +# 3) Each intermediate CA has a parent CA which is either a root CA or another intermediate CA. +# +# This section pertains to configuration of #2 and #3. +# If the "intermediate.parentserver.url" property is set, +# then this is an intermediate CA with the specified parent +# CA. +# +# parentserver section +# url - The URL of the parent server +# caname - Name of the CA to enroll within the server +# +# enrollment section used to enroll intermediate CA with parent CA +# profile - Name of the signing profile to use in issuing the certificate +# label - Label to use in HSM operations +# +# tls section for secure socket connection +# certfiles - PEM-encoded list of trusted root certificate files +# client: +# certfile - PEM-encoded certificate file for when client authentication +# is enabled on server +# keyfile - PEM-encoded key file for when client authentication +# is enabled on server +############################################################################# +intermediate: + parentserver: + url: + caname: + + enrollment: + hosts: + profile: + label: + + tls: + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# CA configuration section +# +# Configure the number of incorrect password attempts are allowed for +# identities. By default, the value of 'passwordattempts' is 10, which +# means that 10 incorrect password attempts can be made before an identity get +# locked out. +############################################################################# +cfg: + identities: + passwordattempts: 10 + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9444 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # require client certificate authentication to access all resources + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushsed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd merics + prefix: server diff --git a/test-network-k8s/config/org2/core.yaml b/test-network-k8s/config/org2/core.yaml new file mode 100644 index 00000000..791af4c3 --- /dev/null +++ b/test-network-k8s/config/org2/core.yaml @@ -0,0 +1,759 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################### +# +# Peer section +# +############################################################################### +peer: + + # The peer id provides a name for this peer instance and is used when + # naming docker resources. + id: jdoe + + # The networkId allows for logical separation of networks and is used when + # naming docker resources. + networkId: dev + + # The Address at local network interface this Peer will listen on. + # By default, it will listen on all network interfaces + listenAddress: 0.0.0.0:7051 + + # The endpoint this peer uses to listen for inbound chaincode connections. + # If this is commented-out, the listen address is selected to be + # the peer's address (see below) with port 7052 + # chaincodeListenAddress: 0.0.0.0:7052 + + # The endpoint the chaincode for this peer uses to connect to the peer. + # If this is not specified, the chaincodeListenAddress address is selected. + # And if chaincodeListenAddress is not specified, address is selected from + # peer address (see below). If specified peer address is invalid then it + # will fallback to the auto detected IP (local IP) regardless of the peer + # addressAutoDetect value. + # chaincodeAddress: 0.0.0.0:7052 + + # When used as peer config, this represents the endpoint to other peers + # in the same organization. For peers in other organization, see + # gossip.externalEndpoint for more info. + # When used as CLI config, this means the peer's endpoint to interact with + address: 0.0.0.0:7051 + + # Whether the Peer should programmatically determine its address + # This case is useful for docker containers. + # When set to true, will override peer address. + addressAutoDetect: false + + # Keepalive settings for peer server and clients + keepalive: + # Interval is the duration after which if the server does not see + # any activity from the client it pings the client to see if it's alive + interval: 7200s + # Timeout is the duration the server waits for a response + # from the client after sending a ping before closing the connection + timeout: 20s + # MinInterval is the minimum permitted time between client pings. + # If clients send pings more frequently, the peer server will + # disconnect them + minInterval: 60s + # Client keepalive settings for communicating with other peer nodes + client: + # Interval is the time between pings to peer nodes. This must + # greater than or equal to the minInterval specified by peer + # nodes + interval: 60s + # Timeout is the duration the client waits for a response from + # peer nodes before closing the connection + timeout: 20s + # DeliveryClient keepalive settings for communication with ordering + # nodes. + deliveryClient: + # Interval is the time between pings to ordering nodes. This must + # greater than or equal to the minInterval specified by ordering + # nodes. + interval: 60s + # Timeout is the duration the client waits for a response from + # ordering nodes before closing the connection + timeout: 20s + + + # Gossip related configuration + gossip: + # Bootstrap set to initialize gossip with. + # This is a list of other peers that this peer reaches out to at startup. + # Important: The endpoints here have to be endpoints of peers in the same + # organization, because the peer would refuse connecting to these endpoints + # unless they are in the same organization as the peer. + bootstrap: 127.0.0.1:7051 + + # NOTE: orgLeader and useLeaderElection parameters are mutual exclusive. + # Setting both to true would result in the termination of the peer + # since this is undefined state. If the peers are configured with + # useLeaderElection=false, make sure there is at least 1 peer in the + # organization that its orgLeader is set to true. + + # Defines whenever peer will initialize dynamic algorithm for + # "leader" selection, where leader is the peer to establish + # connection with ordering service and use delivery protocol + # to pull ledger blocks from ordering service. + useLeaderElection: false + # Statically defines peer to be an organization "leader", + # where this means that current peer will maintain connection + # with ordering service and disseminate block across peers in + # its own organization. Multiple peers or all peers in an organization + # may be configured as org leaders, so that they all pull + # blocks directly from ordering service. + orgLeader: true + + # Interval for membershipTracker polling + membershipTrackerInterval: 5s + + # Overrides the endpoint that the peer publishes to peers + # in its organization. For peers in foreign organizations + # see 'externalEndpoint' + endpoint: + # Maximum count of blocks stored in memory + maxBlockCountToStore: 10 + # Max time between consecutive message pushes(unit: millisecond) + maxPropagationBurstLatency: 10ms + # Max number of messages stored until a push is triggered to remote peers + maxPropagationBurstSize: 10 + # Number of times a message is pushed to remote peers + propagateIterations: 1 + # Number of peers selected to push messages to + propagatePeerNum: 3 + # Determines frequency of pull phases(unit: second) + # Must be greater than digestWaitTime + responseWaitTime + pullInterval: 4s + # Number of peers to pull from + pullPeerNum: 3 + # Determines frequency of pulling state info messages from peers(unit: second) + requestStateInfoInterval: 4s + # Determines frequency of pushing state info messages to peers(unit: second) + publishStateInfoInterval: 4s + # Maximum time a stateInfo message is kept until expired + stateInfoRetentionInterval: + # Time from startup certificates are included in Alive messages(unit: second) + publishCertPeriod: 10s + # Should we skip verifying block messages or not (currently not in use) + skipBlockVerification: false + # Dial timeout(unit: second) + dialTimeout: 3s + # Connection timeout(unit: second) + connTimeout: 2s + # Buffer size of received messages + recvBuffSize: 20 + # Buffer size of sending messages + sendBuffSize: 200 + # Time to wait before pull engine processes incoming digests (unit: second) + # Should be slightly smaller than requestWaitTime + digestWaitTime: 1s + # Time to wait before pull engine removes incoming nonce (unit: milliseconds) + # Should be slightly bigger than digestWaitTime + requestWaitTime: 1500ms + # Time to wait before pull engine ends pull (unit: second) + responseWaitTime: 2s + # Alive check interval(unit: second) + aliveTimeInterval: 5s + # Alive expiration timeout(unit: second) + aliveExpirationTimeout: 25s + # Reconnect interval(unit: second) + reconnectInterval: 25s + # Max number of attempts to connect to a peer + maxConnectionAttempts: 120 + # Message expiration factor for alive messages + msgExpirationFactor: 20 + # This is an endpoint that is published to peers outside of the organization. + # If this isn't set, the peer will not be known to other organizations. + externalEndpoint: + # Leader election service configuration + election: + # Longest time peer waits for stable membership during leader election startup (unit: second) + startupGracePeriod: 15s + # Interval gossip membership samples to check its stability (unit: second) + membershipSampleInterval: 1s + # Time passes since last declaration message before peer decides to perform leader election (unit: second) + leaderAliveThreshold: 10s + # Time between peer sends propose message and declares itself as a leader (sends declaration message) (unit: second) + leaderElectionDuration: 5s + + pvtData: + # pullRetryThreshold determines the maximum duration of time private data corresponding for a given block + # would be attempted to be pulled from peers until the block would be committed without the private data + pullRetryThreshold: 60s + # As private data enters the transient store, it is associated with the peer's ledger's height at that time. + # transientstoreMaxBlockRetention defines the maximum difference between the current ledger's height upon commit, + # and the private data residing inside the transient store that is guaranteed not to be purged. + # Private data is purged from the transient store when blocks with sequences that are multiples + # of transientstoreMaxBlockRetention are committed. + transientstoreMaxBlockRetention: 1000 + # pushAckTimeout is the maximum time to wait for an acknowledgement from each peer + # at private data push at endorsement time. + pushAckTimeout: 3s + # Block to live pulling margin, used as a buffer + # to prevent peer from trying to pull private data + # from peers that is soon to be purged in next N blocks. + # This helps a newly joined peer catch up to current + # blockchain height quicker. + btlPullMargin: 10 + # the process of reconciliation is done in an endless loop, while in each iteration reconciler tries to + # pull from the other peers the most recent missing blocks with a maximum batch size limitation. + # reconcileBatchSize determines the maximum batch size of missing private data that will be reconciled in a + # single iteration. + reconcileBatchSize: 10 + # reconcileSleepInterval determines the time reconciler sleeps from end of an iteration until the beginning + # of the next reconciliation iteration. + reconcileSleepInterval: 1m + # reconciliationEnabled is a flag that indicates whether private data reconciliation is enable or not. + reconciliationEnabled: true + # skipPullingInvalidTransactionsDuringCommit is a flag that indicates whether pulling of invalid + # transaction's private data from other peers need to be skipped during the commit time and pulled + # only through reconciler. + skipPullingInvalidTransactionsDuringCommit: false + # implicitCollectionDisseminationPolicy specifies the dissemination policy for the peer's own implicit collection. + # When a peer endorses a proposal that writes to its own implicit collection, below values override the default values + # for disseminating private data. + # Note that it is applicable to all channels the peer has joined. The implication is that requiredPeerCount has to + # be smaller than the number of peers in a channel that has the lowest numbers of peers from the organization. + implicitCollectionDisseminationPolicy: + # requiredPeerCount defines the minimum number of eligible peers to which the peer must successfully + # disseminate private data for its own implicit collection during endorsement. Default value is 0. + requiredPeerCount: 0 + # maxPeerCount defines the maximum number of eligible peers to which the peer will attempt to + # disseminate private data for its own implicit collection during endorsement. Default value is 1. + maxPeerCount: 1 + + # Gossip state transfer related configuration + state: + # indicates whenever state transfer is enabled or not + # default value is true, i.e. state transfer is active + # and takes care to sync up missing blocks allowing + # lagging peer to catch up to speed with rest network. + # Keep in mind that when peer.gossip.useLeaderElection is true + # and there are several peers in the organization, + # or peer.gossip.useLeaderElection is false alongside with + # peer.gossip.orgleader being false, the peer's ledger may lag behind + # the rest of the peers and will never catch up due to state transfer + # being disabled. + enabled: false + # checkInterval interval to check whether peer is lagging behind enough to + # request blocks via state transfer from another peer. + checkInterval: 10s + # responseTimeout amount of time to wait for state transfer response from + # other peers + responseTimeout: 3s + # batchSize the number of blocks to request via state transfer from another peer + batchSize: 10 + # blockBufferSize reflects the size of the re-ordering buffer + # which captures blocks and takes care to deliver them in order + # down to the ledger layer. The actual buffer size is bounded between + # 0 and 2*blockBufferSize, each channel maintains its own buffer + blockBufferSize: 20 + # maxRetries maximum number of re-tries to ask + # for single state transfer request + maxRetries: 3 + + # TLS Settings + tls: + # Require server-side TLS + enabled: true + # Require client certificates / mutual TLS for inbound connections. + # Note that clients that are not configured to use a certificate will + # fail to connect to the peer. + clientAuthRequired: false + # X.509 certificate used for TLS server + cert: + file: tls/server.crt + # Private key used for TLS server + key: + file: tls/server.key + # rootcert.file represents the trusted root certificate chain used for verifying certificates + # of other nodes during outbound connections. + # It is not required to be set, but can be used to augment the set of TLS CA certificates + # available from the MSPs of each channel’s configuration. + rootcert: + file: tls/ca.crt + # If mutual TLS is enabled, clientRootCAs.files contains a list of additional root certificates + # used for verifying certificates of client connections. + # It augments the set of TLS CA certificates available from the MSPs of each channel’s configuration. + # Minimally, set your organization's TLS CA root certificate so that the peer can receive join channel requests. + clientRootCAs: + files: + - tls/ca.crt + # Private key used for TLS when making client connections. + # If not set, peer.tls.key.file will be used instead + clientKey: + file: + # X.509 certificate used for TLS when making client connections. + # If not set, peer.tls.cert.file will be used instead + clientCert: + file: + + # Authentication contains configuration parameters related to authenticating + # client messages + authentication: + # the acceptable difference between the current server time and the + # client's time as specified in a client request message + timewindow: 15m + + # Path on the file system where peer will store data (eg ledger). This + # location must be access control protected to prevent unintended + # modification that might corrupt the peer operations. + fileSystemPath: /var/hyperledger/production + + # BCCSP (Blockchain crypto provider): Select which crypto implementation or + # library to use + BCCSP: + Default: SW + # Settings for the SW crypto provider (i.e. when DEFAULT: SW) + SW: + # TODO: The default Hash and Security level needs refactoring to be + # fully configurable. Changing these defaults requires coordination + # SHA2 is hardcoded in several places, not only BCCSP + Hash: SHA2 + Security: 256 + # Location of Key Store + FileKeyStore: + # If "", defaults to 'mspConfigPath'/keystore + KeyStore: + # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) + PKCS11: + # Location of the PKCS11 module library + Library: + # Token Label + Label: + # User PIN + Pin: + Hash: + Security: + + # Path on the file system where peer will find MSP local configurations + mspConfigPath: msp + + # Identifier of the local MSP + # ----!!!!IMPORTANT!!!-!!!IMPORTANT!!!-!!!IMPORTANT!!!!---- + # Deployers need to change the value of the localMspId string. + # In particular, the name of the local MSP ID of a peer needs + # to match the name of one of the MSPs in each of the channel + # that this peer is a member of. Otherwise this peer's messages + # will not be identified as valid by other nodes. + localMspId: Org2MSP + + # CLI common client config options + client: + # connection timeout + connTimeout: 3s + + # Delivery service related config + deliveryclient: + # It sets the total time the delivery service may spend in reconnection + # attempts until its retry logic gives up and returns an error + reconnectTotalTimeThreshold: 3600s + + # It sets the delivery service <-> ordering service node connection timeout + connTimeout: 3s + + # It sets the delivery service maximal delay between consecutive retries + reConnectBackoffThreshold: 3600s + + # A list of orderer endpoint addresses which should be overridden + # when found in channel configurations. + addressOverrides: + # - from: + # to: + # caCertsFile: + # - from: + # to: + # caCertsFile: + + # Type for the local MSP - by default it's of type bccsp + localMspType: bccsp + + # Used with Go profiling tools only in none production environment. In + # production, it should be disabled (eg enabled: false) + profile: + enabled: false + listenAddress: 0.0.0.0:6060 + + # Handlers defines custom handlers that can filter and mutate + # objects passing within the peer, such as: + # Auth filter - reject or forward proposals from clients + # Decorators - append or mutate the chaincode input passed to the chaincode + # Endorsers - Custom signing over proposal response payload and its mutation + # Valid handler definition contains: + # - A name which is a factory method name defined in + # core/handlers/library/library.go for statically compiled handlers + # - library path to shared object binary for pluggable filters + # Auth filters and decorators are chained and executed in the order that + # they are defined. For example: + # authFilters: + # - + # name: FilterOne + # library: /opt/lib/filter.so + # - + # name: FilterTwo + # decorators: + # - + # name: DecoratorOne + # - + # name: DecoratorTwo + # library: /opt/lib/decorator.so + # Endorsers are configured as a map that its keys are the endorsement system chaincodes that are being overridden. + # Below is an example that overrides the default ESCC and uses an endorsement plugin that has the same functionality + # as the default ESCC. + # If the 'library' property is missing, the name is used as the constructor method in the builtin library similar + # to auth filters and decorators. + # endorsers: + # escc: + # name: DefaultESCC + # library: /etc/hyperledger/fabric/plugin/escc.so + handlers: + authFilters: + - + name: DefaultAuth + - + name: ExpirationCheck # This filter checks identity x509 certificate expiration + decorators: + - + name: DefaultDecorator + endorsers: + escc: + name: DefaultEndorsement + library: + validators: + vscc: + name: DefaultValidation + library: + + # library: /etc/hyperledger/fabric/plugin/escc.so + # Number of goroutines that will execute transaction validation in parallel. + # By default, the peer chooses the number of CPUs on the machine. Set this + # variable to override that choice. + # NOTE: overriding this value might negatively influence the performance of + # the peer so please change this value only if you know what you're doing + validatorPoolSize: + + # The discovery service is used by clients to query information about peers, + # such as - which peers have joined a certain channel, what is the latest + # channel config, and most importantly - given a chaincode and a channel, + # what possible sets of peers satisfy the endorsement policy. + discovery: + enabled: true + # Whether the authentication cache is enabled or not. + authCacheEnabled: true + # The maximum size of the cache, after which a purge takes place + authCacheMaxSize: 1000 + # The proportion (0 to 1) of entries that remain in the cache after the cache is purged due to overpopulation + authCachePurgeRetentionRatio: 0.75 + # Whether to allow non-admins to perform non channel scoped queries. + # When this is false, it means that only peer admins can perform non channel scoped queries. + orgMembersAllowedAccess: false + + # Limits is used to configure some internal resource limits. + limits: + # Concurrency limits the number of concurrently running requests to a service on each peer. + # Currently this option is only applied to endorser service and deliver service. + # When the property is missing or the value is 0, the concurrency limit is disabled for the service. + concurrency: + # endorserService limits concurrent requests to endorser service that handles chaincode deployment, query and invocation, + # including both user chaincodes and system chaincodes. + endorserService: 2500 + # deliverService limits concurrent event listeners registered to deliver service for blocks and transaction events. + deliverService: 2500 + +############################################################################### +# +# VM section +# +############################################################################### +vm: + + # Endpoint of the vm management system. For docker can be one of the following in general + # unix:///var/run/docker.sock + # http://localhost:2375 + # https://localhost:2376 + endpoint: unix:///var/run/docker.sock + + # settings for docker vms + docker: + tls: + enabled: false + ca: + file: docker/ca.crt + cert: + file: docker/tls.crt + key: + file: docker/tls.key + + # Enables/disables the standard out/err from chaincode containers for + # debugging purposes + attachStdout: false + + # Parameters on creating docker container. + # Container may be efficiently created using ipam & dns-server for cluster + # NetworkMode - sets the networking mode for the container. Supported + # standard values are: `host`(default),`bridge`,`ipvlan`,`none`. + # Dns - a list of DNS servers for the container to use. + # Note: `Privileged` `Binds` `Links` and `PortBindings` properties of + # Docker Host Config are not supported and will not be used if set. + # LogConfig - sets the logging driver (Type) and related options + # (Config) for Docker. For more info, + # https://docs.docker.com/engine/admin/logging/overview/ + # Note: Set LogConfig using Environment Variables is not supported. + hostConfig: + NetworkMode: host + Dns: + # - 192.168.0.1 + LogConfig: + Type: json-file + Config: + max-size: "50m" + max-file: "5" + Memory: 2147483648 + +############################################################################### +# +# Chaincode section +# +############################################################################### +chaincode: + + # The id is used by the Chaincode stub to register the executing Chaincode + # ID with the Peer and is generally supplied through ENV variables + # the `path` form of ID is provided when installing the chaincode. + # The `name` is used for all other requests and can be any string. + id: + path: + name: + + # Generic builder environment, suitable for most chaincode types + builder: $(DOCKER_NS)/fabric-ccenv:$(TWO_DIGIT_VERSION) + + # Enables/disables force pulling of the base docker images (listed below) + # during user chaincode instantiation. + # Useful when using moving image tags (such as :latest) + pull: false + + golang: + # golang will never need more than baseos + runtime: $(DOCKER_NS)/fabric-baseos:$(TWO_DIGIT_VERSION) + + # whether or not golang chaincode should be linked dynamically + dynamicLink: false + + java: + # This is an image based on java:openjdk-8 with addition compiler + # tools added for java shim layer packaging. + # This image is packed with shim layer libraries that are necessary + # for Java chaincode runtime. + runtime: $(DOCKER_NS)/fabric-javaenv:$(TWO_DIGIT_VERSION) + + node: + # This is an image based on node:$(NODE_VER)-alpine + runtime: $(DOCKER_NS)/fabric-nodeenv:$(TWO_DIGIT_VERSION) + + # 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: + - path: /var/hyperledger/fabric/chaincode/ccs-builder + name: ccs-builder + propagateEnvironment: + - HOME + - CORE_PEER_ID + - CORE_PEER_LOCALMSPID + + # The maximum duration to wait for the chaincode build and install process + # to complete. + installTimeout: 300s + + # Timeout duration for starting up a container and waiting for Register + # to come through. + startuptimeout: 300s + + # Timeout duration for Invoke and Init calls to prevent runaway. + # This timeout is used by all chaincodes in all the channels, including + # system chaincodes. + # Note that during Invoke, if the image is not available (e.g. being + # cleaned up when in development environment), the peer will automatically + # build the image, which might take more time. In production environment, + # the chaincode image is unlikely to be deleted, so the timeout could be + # reduced accordingly. + executetimeout: 30s + + # There are 2 modes: "dev" and "net". + # In dev mode, user runs the chaincode after starting peer from + # command line on local machine. + # In net mode, peer will run chaincode in a docker container. + mode: net + + # keepalive in seconds. In situations where the communication goes through a + # proxy that does not support keep-alive, this parameter will maintain connection + # between peer and chaincode. + # A value <= 0 turns keepalive off + keepalive: 0 + + # enabled system chaincodes + system: + _lifecycle: enable + cscc: enable + lscc: enable + qscc: enable + + # Logging section for the chaincode container + logging: + # Default level for all loggers within the chaincode container + level: info + # Override default level for the 'shim' logger + shim: warning + # Format for the chaincode container logs + format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}' + +############################################################################### +# +# Ledger section - ledger configuration encompasses both the blockchain +# and the state +# +############################################################################### +ledger: + + blockchain: + + state: + # stateDatabase - options are "goleveldb", "CouchDB" + # goleveldb - default state database stored in goleveldb. + # CouchDB - store state database in CouchDB + stateDatabase: goleveldb + # Limit on the number of records to return per query + totalQueryLimit: 100000 + couchDBConfig: + # It is recommended to run CouchDB on the same server as the peer, and + # not map the CouchDB container port to a server port in docker-compose. + # Otherwise proper security must be provided on the connection between + # CouchDB client (on the peer) and server. + couchDBAddress: 127.0.0.1:5984 + # This username must have read and write authority on CouchDB + username: + # The password is recommended to pass as an environment variable + # during start up (eg CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD). + # If it is stored here, the file must be access control protected + # to prevent unintended users from discovering the password. + password: + # Number of retries for CouchDB errors + maxRetries: 3 + # Number of retries for CouchDB errors during peer startup. + # The delay between retries doubles for each attempt. + # Default of 10 retries results in 11 attempts over 2 minutes. + maxRetriesOnStartup: 10 + # CouchDB request timeout (unit: duration, e.g. 20s) + requestTimeout: 35s + # Limit on the number of records per each CouchDB query + # Note that chaincode queries are only bound by totalQueryLimit. + # Internally the chaincode may execute multiple CouchDB queries, + # each of size internalQueryLimit. + internalQueryLimit: 1000 + # Limit on the number of records per CouchDB bulk update batch + maxBatchUpdateSize: 1000 + # Warm indexes after every N blocks. + # This option warms any indexes that have been + # deployed to CouchDB after every N blocks. + # A value of 1 will warm indexes after every block commit, + # to ensure fast selector queries. + # Increasing the value may improve write efficiency of peer and CouchDB, + # but may degrade query response time. + warmIndexesAfterNBlocks: 1 + # Create the _global_changes system database + # This is optional. Creating the global changes database will require + # additional system resources to track changes and maintain the database + createGlobalChangesDB: false + # CacheSize denotes the maximum mega bytes (MB) to be allocated for the in-memory state + # cache. Note that CacheSize needs to be a multiple of 32 MB. If it is not a multiple + # of 32 MB, the peer would round the size to the next multiple of 32 MB. + # To disable the cache, 0 MB needs to be assigned to the cacheSize. + cacheSize: 64 + + history: + # enableHistoryDatabase - options are true or false + # Indicates if the history of key updates should be stored. + # All history 'index' will be stored in goleveldb, regardless if using + # CouchDB or alternate database for the state. + enableHistoryDatabase: true + + pvtdataStore: + # the maximum db batch size for converting + # the ineligible missing data entries to eligible missing data entries + collElgProcMaxDbBatchSize: 5000 + # the minimum duration (in milliseconds) between writing + # two consecutive db batches for converting the ineligible missing data entries to eligible missing data entries + collElgProcDbBatchesInterval: 1000 + # The missing data entries are classified into two categories: + # (1) prioritized + # (2) deprioritized + # Initially, all missing data are in the prioritized list. When the + # reconciler is unable to fetch the missing data from other peers, + # the unreconciled missing data would be moved to the deprioritized list. + # The reconciler would retry deprioritized missing data after every + # deprioritizedDataReconcilerInterval (unit: minutes). Note that the + # interval needs to be greater than the reconcileSleepInterval + deprioritizedDataReconcilerInterval: 60m + + snapshots: + # Path on the file system where peer will store ledger snapshots + rootDir: /var/hyperledger/production/snapshots + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9443 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # most operations service endpoints require client authentication when TLS + # is enabled. clientAuthRequired requires client certificate authentication + # at the TLS layer to access all resources. + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # metrics provider is one of statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd metrics + prefix: diff --git a/test-network-k8s/config/org2/fabric-ecert-ca-server-config.yaml b/test-network-k8s/config/org2/fabric-ecert-ca-server-config.yaml new file mode 100644 index 00000000..23732ff8 --- /dev/null +++ b/test-network-k8s/config/org2/fabric-ecert-ca-server-config.yaml @@ -0,0 +1,506 @@ +############################################################################# +# This is a configuration file for the fabric-ca-server command. +# +# COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES +# ------------------------------------------------ +# Each configuration element can be overridden via command line +# arguments or environment variables. The precedence for determining +# the value of each element is as follows: +# 1) command line argument +# Examples: +# a) --port 443 +# To set the listening port +# b) --ca.keyfile ../mykey.pem +# To set the "keyfile" element in the "ca" section below; +# note the '.' separator character. +# 2) environment variable +# Examples: +# a) FABRIC_CA_SERVER_PORT=443 +# To set the listening port +# b) FABRIC_CA_SERVER_CA_KEYFILE="../mykey.pem" +# To set the "keyfile" element in the "ca" section below; +# note the '_' separator character. +# 3) configuration file +# 4) default value (if there is one) +# All default values are shown beside each element below. +# +# FILE NAME ELEMENTS +# ------------------ +# The value of all fields whose name ends with "file" or "files" are +# name or names of other files. +# For example, see "tls.certfile" and "tls.clientauth.certfiles". +# The value of each of these fields can be a simple filename, a +# relative path, or an absolute path. If the value is not an +# absolute path, it is interpretted as being relative to the location +# of this configuration file. +# +############################################################################# + +# Version of config file +version: 1.5.2 + +# Server's listening port (default: 7054) +port: 443 + +# Cross-Origin Resource Sharing (CORS) +cors: + enabled: false + origins: + - "*" + +# Enables debug logging (default: false) +debug: false + +# Size limit of an acceptable CRL in bytes (default: 512000) +crlsizelimit: 512000 + +############################################################################# +# TLS section for the server's listening port +# +# The following types are supported for client authentication: NoClientCert, +# RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, +# and RequireAndVerifyClientCert. +# +# Certfiles is a list of root certificate authorities that the server uses +# when verifying client certificates. +############################################################################# +tls: + # Enable TLS (default: false) + enabled: true + # TLS for the server's listening port + certfile: + keyfile: + clientauth: + type: noclientcert + certfiles: + +############################################################################# +# The CA section contains information related to the Certificate Authority +# including the name of the CA, which should be unique for all members +# of a blockchain network. It also includes the key and certificate files +# used when issuing enrollment certificates (ECerts) and transaction +# certificates (TCerts). +# The chainfile (if it exists) contains the certificate chain which +# should be trusted for this CA, where the 1st in the chain is always the +# root CA certificate. +############################################################################# +ca: + # Name of this CA + name: org2-ecert-ca + # Key file (is only used to import a private key into BCCSP) + keyfile: + # Certificate file (default: ca-cert.pem) + certfile: + # Chain file + chainfile: + +############################################################################# +# The gencrl REST endpoint is used to generate a CRL that contains revoked +# certificates. This section contains configuration options that are used +# during gencrl request processing. +############################################################################# +crl: + # Specifies expiration for the generated CRL. The number of hours + # specified by this property is added to the UTC time, the resulting time + # is used to set the 'Next Update' date of the CRL. + expiry: 24h + +############################################################################# +# The registry section controls how the fabric-ca-server does two things: +# 1) authenticates enrollment requests which contain a username and password +# (also known as an enrollment ID and secret). +# 2) once authenticated, retrieves the identity's attribute names and +# values which the fabric-ca-server optionally puts into TCerts +# which it issues for transacting on the Hyperledger Fabric blockchain. +# These attributes are useful for making access control decisions in +# chaincode. +# There are two main configuration options: +# 1) The fabric-ca-server is the registry. +# This is true if "ldap.enabled" in the ldap section below is false. +# 2) An LDAP server is the registry, in which case the fabric-ca-server +# calls the LDAP server to perform these tasks. +# This is true if "ldap.enabled" in the ldap section below is true, +# which means this "registry" section is ignored. +############################################################################# +registry: + # Maximum number of times a password/secret can be reused for enrollment + # (default: -1, which means there is no limit) + maxenrollments: -1 + + # Contains identity information which is used when LDAP is disabled + identities: + - name: rcaadmin + pass: rcaadminpw + type: client + affiliation: "" + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + +############################################################################# +# Database section +# Supported types are: "sqlite3", "postgres", and "mysql". +# The datasource value depends on the type. +# If the type is "sqlite3", the datasource value is a file name to use +# as the database store. Since "sqlite3" is an embedded database, it +# may not be used if you want to run the fabric-ca-server in a cluster. +# To run the fabric-ca-server in a cluster, you must choose "postgres" +# or "mysql". +############################################################################# +db: + type: sqlite3 + datasource: fabric-ca-server.db + tls: + enabled: false + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# LDAP section +# If LDAP is enabled, the fabric-ca-server calls LDAP to: +# 1) authenticate enrollment ID and secret (i.e. username and password) +# for enrollment requests; +# 2) To retrieve identity attributes +############################################################################# +ldap: + # Enables or disables the LDAP client (default: false) + # If this is set to true, the "registry" section is ignored. + enabled: false + # The URL of the LDAP server + url: ldap://:@:/ + # TLS configuration for the client connection to the LDAP server + tls: + certfiles: + client: + certfile: + keyfile: + # Attribute related configuration for mapping from LDAP entries to Fabric CA attributes + attribute: + # 'names' is an array of strings containing the LDAP attribute names which are + # requested from the LDAP server for an LDAP identity's entry + names: ['uid','member'] + # The 'converters' section is used to convert an LDAP entry to the value of + # a fabric CA attribute. + # For example, the following converts an LDAP 'uid' attribute + # whose value begins with 'revoker' to a fabric CA attribute + # named "hf.Revoker" with a value of "true" (because the boolean expression + # evaluates to true). + # converters: + # - name: hf.Revoker + # value: attr("uid") =~ "revoker*" + converters: + - name: + value: + # The 'maps' section contains named maps which may be referenced by the 'map' + # function in the 'converters' section to map LDAP responses to arbitrary values. + # For example, assume a user has an LDAP attribute named 'member' which has multiple + # values which are each a distinguished name (i.e. a DN). For simplicity, assume the + # values of the 'member' attribute are 'dn1', 'dn2', and 'dn3'. + # Further assume the following configuration. + # converters: + # - name: hf.Registrar.Roles + # value: map(attr("member"),"groups") + # maps: + # groups: + # - name: dn1 + # value: peer + # - name: dn2 + # value: client + # The value of the user's 'hf.Registrar.Roles' attribute is then computed to be + # "peer,client,dn3". This is because the value of 'attr("member")' is + # "dn1,dn2,dn3", and the call to 'map' with a 2nd argument of + # "group" replaces "dn1" with "peer" and "dn2" with "client". + maps: + groups: + - name: + value: + +############################################################################# +# Affiliations section. Fabric CA server can be bootstrapped with the +# affiliations specified in this section. Affiliations are specified as maps. +# For example: +# businessunit1: +# department1: +# - team1 +# businessunit2: +# - department2 +# - department3 +# +# Affiliations are hierarchical in nature. In the above example, +# department1 (used as businessunit1.department1) is the child of businessunit1. +# team1 (used as businessunit1.department1.team1) is the child of department1. +# department2 (used as businessunit2.department2) and department3 (businessunit2.department3) +# are children of businessunit2. +# Note: Affiliations are case sensitive except for the non-leaf affiliations +# (like businessunit1, department1, businessunit2) that are specified in the configuration file, +# which are always stored in lower case. +############################################################################# +affiliations: + org1: + - department1 + - department2 + org2: + - department1 + +############################################################################# +# Signing section +# +# The "default" subsection is used to sign enrollment certificates; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +# +# The "ca" profile subsection is used to sign intermediate CA certificates; +# the default expiration ("expiry" field) is "43800h" which is 5 years in hours. +# Note that "isca" is true, meaning that it issues a CA certificate. +# A maxpathlen of 0 means that the intermediate CA cannot issue other +# intermediate CA certificates, though it can still issue end entity certificates. +# (See RFC 5280, section 4.2.1.9) +# +# The "tls" profile subsection is used to sign TLS certificate requests; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +############################################################################# +signing: + default: + usage: + - digital signature + expiry: 8760h + profiles: + ca: + usage: + - cert sign + - crl sign + expiry: 43800h + caconstraint: + isca: true + maxpathlen: 0 + tls: + usage: + - signing + - key encipherment + - server auth + - client auth + - key agreement + expiry: 8760h + +########################################################################### +# Certificate Signing Request (CSR) section. +# This controls the creation of the root CA certificate. +# The expiration for the root CA certificate is configured with the +# "ca.expiry" field below, whose default value is "131400h" which is +# 15 years in hours. +# The pathlength field is used to limit CA certificate hierarchy as described +# in section 4.2.1.9 of RFC 5280. +# Examples: +# 1) No pathlength value means no limit is requested. +# 2) pathlength == 1 means a limit of 1 is requested which is the default for +# a root CA. This means the root CA can issue intermediate CA certificates, +# but these intermediate CAs may not in turn issue other CA certificates +# though they can still issue end entity certificates. +# 3) pathlength == 0 means a limit of 0 is requested; +# this is the default for an intermediate CA, which means it can not issue +# CA certificates though it can still issue end entity certificates. +########################################################################### +csr: + cn: fabric-ca-server + keyrequest: + algo: ecdsa + size: 256 + names: + - C: US + ST: "North Carolina" + L: + O: Hyperledger + OU: Fabric + hosts: + - localhost + - 127.0.0.1 + - org2-ecert-ca + - org2-ecert-ca.test-network.svc.cluster.local + ca: + expiry: 131400h + pathlength: 1 + +########################################################################### +# Each CA can issue both X509 enrollment certificate as well as Idemix +# Credential. This section specifies configuration for the issuer component +# that is responsible for issuing Idemix credentials. +########################################################################### +idemix: + # Specifies pool size for revocation handles. A revocation handle is an unique identifier of an + # Idemix credential. The issuer will create a pool revocation handles of this specified size. When + # a credential is requested, issuer will get handle from the pool and assign it to the credential. + # Issuer will repopulate the pool with new handles when the last handle in the pool is used. + # A revocation handle and credential revocation information (CRI) are used to create non revocation proof + # by the prover to prove to the verifier that her credential is not revoked. + rhpoolsize: 1000 + + # The Idemix credential issuance is a two step process. First step is to get a nonce from the issuer + # and second step is send credential request that is constructed using the nonce to the isuser to + # request a credential. This configuration property specifies expiration for the nonces. By default is + # nonces expire after 15 seconds. The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration). + nonceexpiration: 15s + + # Specifies interval at which expired nonces are removed from datastore. Default value is 15 minutes. + # The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration) + noncesweepinterval: 15m + +############################################################################# +# BCCSP (BlockChain Crypto Service Provider) section is used to select which +# crypto library implementation to use +############################################################################# +bccsp: + default: SW + sw: + hash: SHA2 + security: 256 + filekeystore: + # The directory used for the software file-based keystore + keystore: msp/keystore + +############################################################################# +# Multi CA section +# +# Each Fabric CA server contains one CA by default. This section is used +# to configure multiple CAs in a single server. +# +# 1) --cacount +# Automatically generate non-default CAs. The names of these +# additional CAs are "ca1", "ca2", ... "caN", where "N" is +# This is particularly useful in a development environment to quickly set up +# multiple CAs. Note that, this config option is not applicable to intermediate CA server +# i.e., Fabric CA server that is started with intermediate.parentserver.url config +# option (-u command line option) +# +# 2) --cafiles +# For each CA config file in the list, generate a separate signing CA. Each CA +# config file in this list MAY contain all of the same elements as are found in +# the server config file except port, debug, and tls sections. +# +# Examples: +# fabric-ca-server start -b admin:adminpw --cacount 2 +# +# fabric-ca-server start -b admin:adminpw --cafiles ca/ca1/fabric-ca-server-config.yaml +# --cafiles ca/ca2/fabric-ca-server-config.yaml +# +############################################################################# + +cacount: + +cafiles: + +############################################################################# +# Intermediate CA section +# +# The relationship between servers and CAs is as follows: +# 1) A single server process may contain or function as one or more CAs. +# This is configured by the "Multi CA section" above. +# 2) Each CA is either a root CA or an intermediate CA. +# 3) Each intermediate CA has a parent CA which is either a root CA or another intermediate CA. +# +# This section pertains to configuration of #2 and #3. +# If the "intermediate.parentserver.url" property is set, +# then this is an intermediate CA with the specified parent +# CA. +# +# parentserver section +# url - The URL of the parent server +# caname - Name of the CA to enroll within the server +# +# enrollment section used to enroll intermediate CA with parent CA +# profile - Name of the signing profile to use in issuing the certificate +# label - Label to use in HSM operations +# +# tls section for secure socket connection +# certfiles - PEM-encoded list of trusted root certificate files +# client: +# certfile - PEM-encoded certificate file for when client authentication +# is enabled on server +# keyfile - PEM-encoded key file for when client authentication +# is enabled on server +############################################################################# +intermediate: + parentserver: + url: + caname: + + enrollment: + hosts: + profile: + label: + + tls: + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# CA configuration section +# +# Configure the number of incorrect password attempts are allowed for +# identities. By default, the value of 'passwordattempts' is 10, which +# means that 10 incorrect password attempts can be made before an identity get +# locked out. +############################################################################# +cfg: + identities: + passwordattempts: 10 + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9443 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # require client certificate authentication to access all resources + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushsed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd merics + prefix: server diff --git a/test-network-k8s/config/org2/fabric-tls-ca-server-config.yaml b/test-network-k8s/config/org2/fabric-tls-ca-server-config.yaml new file mode 100644 index 00000000..74879302 --- /dev/null +++ b/test-network-k8s/config/org2/fabric-tls-ca-server-config.yaml @@ -0,0 +1,496 @@ +############################################################################# +# This is a configuration file for the fabric-ca-server command. +# +# COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES +# ------------------------------------------------ +# Each configuration element can be overridden via command line +# arguments or environment variables. The precedence for determining +# the value of each element is as follows: +# 1) command line argument +# Examples: +# a) --port 443 +# To set the listening port +# b) --ca.keyfile ../mykey.pem +# To set the "keyfile" element in the "ca" section below; +# note the '.' separator character. +# 2) environment variable +# Examples: +# a) FABRIC_CA_SERVER_PORT=443 +# To set the listening port +# b) FABRIC_CA_SERVER_CA_KEYFILE="../mykey.pem" +# To set the "keyfile" element in the "ca" section below; +# note the '_' separator character. +# 3) configuration file +# 4) default value (if there is one) +# All default values are shown beside each element below. +# +# FILE NAME ELEMENTS +# ------------------ +# The value of all fields whose name ends with "file" or "files" are +# name or names of other files. +# For example, see "tls.certfile" and "tls.clientauth.certfiles". +# The value of each of these fields can be a simple filename, a +# relative path, or an absolute path. If the value is not an +# absolute path, it is interpretted as being relative to the location +# of this configuration file. +# +############################################################################# + +# Version of config file +version: 1.5.2 + +# Server's listening port (default: 7054) +port: 443 + +# Cross-Origin Resource Sharing (CORS) +cors: + enabled: false + origins: + - "*" + +# Enables debug logging (default: false) +debug: false + +# Size limit of an acceptable CRL in bytes (default: 512000) +crlsizelimit: 512000 + +############################################################################# +# TLS section for the server's listening port +# +# The following types are supported for client authentication: NoClientCert, +# RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, +# and RequireAndVerifyClientCert. +# +# Certfiles is a list of root certificate authorities that the server uses +# when verifying client certificates. +############################################################################# +tls: + # Enable TLS (default: false) + enabled: true + # TLS for the server's listening port + certfile: + keyfile: + clientauth: + type: noclientcert + certfiles: + +############################################################################# +# The CA section contains information related to the Certificate Authority +# including the name of the CA, which should be unique for all members +# of a blockchain network. It also includes the key and certificate files +# used when issuing enrollment certificates (ECerts) and transaction +# certificates (TCerts). +# The chainfile (if it exists) contains the certificate chain which +# should be trusted for this CA, where the 1st in the chain is always the +# root CA certificate. +############################################################################# +ca: + # Name of this CA + name: org2-tls-ca + # Key file (is only used to import a private key into BCCSP) + keyfile: + # Certificate file (default: ca-cert.pem) + certfile: + # Chain file + chainfile: + +############################################################################# +# The gencrl REST endpoint is used to generate a CRL that contains revoked +# certificates. This section contains configuration options that are used +# during gencrl request processing. +############################################################################# +crl: + # Specifies expiration for the generated CRL. The number of hours + # specified by this property is added to the UTC time, the resulting time + # is used to set the 'Next Update' date of the CRL. + expiry: 24h + +############################################################################# +# The registry section controls how the fabric-ca-server does two things: +# 1) authenticates enrollment requests which contain a username and password +# (also known as an enrollment ID and secret). +# 2) once authenticated, retrieves the identity's attribute names and +# values which the fabric-ca-server optionally puts into TCerts +# which it issues for transacting on the Hyperledger Fabric blockchain. +# These attributes are useful for making access control decisions in +# chaincode. +# There are two main configuration options: +# 1) The fabric-ca-server is the registry. +# This is true if "ldap.enabled" in the ldap section below is false. +# 2) An LDAP server is the registry, in which case the fabric-ca-server +# calls the LDAP server to perform these tasks. +# This is true if "ldap.enabled" in the ldap section below is true, +# which means this "registry" section is ignored. +############################################################################# +registry: + # Maximum number of times a password/secret can be reused for enrollment + # (default: -1, which means there is no limit) + maxenrollments: -1 + + # Contains identity information which is used when LDAP is disabled + identities: + - name: tlsadmin + pass: tlsadminpw + type: client + affiliation: "" + attrs: + hf.Registrar.Roles: "*" + hf.Registrar.DelegateRoles: "*" + hf.Revoker: true + hf.IntermediateCA: true + hf.GenCRL: true + hf.Registrar.Attributes: "*" + hf.AffiliationMgr: true + +############################################################################# +# Database section +# Supported types are: "sqlite3", "postgres", and "mysql". +# The datasource value depends on the type. +# If the type is "sqlite3", the datasource value is a file name to use +# as the database store. Since "sqlite3" is an embedded database, it +# may not be used if you want to run the fabric-ca-server in a cluster. +# To run the fabric-ca-server in a cluster, you must choose "postgres" +# or "mysql". +############################################################################# +db: + type: sqlite3 + datasource: fabric-ca-server.db + tls: + enabled: false + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# LDAP section +# If LDAP is enabled, the fabric-ca-server calls LDAP to: +# 1) authenticate enrollment ID and secret (i.e. username and password) +# for enrollment requests; +# 2) To retrieve identity attributes +############################################################################# +ldap: + # Enables or disables the LDAP client (default: false) + # If this is set to true, the "registry" section is ignored. + enabled: false + # The URL of the LDAP server + url: ldap://:@:/ + # TLS configuration for the client connection to the LDAP server + tls: + certfiles: + client: + certfile: + keyfile: + # Attribute related configuration for mapping from LDAP entries to Fabric CA attributes + attribute: + # 'names' is an array of strings containing the LDAP attribute names which are + # requested from the LDAP server for an LDAP identity's entry + names: ['uid','member'] + # The 'converters' section is used to convert an LDAP entry to the value of + # a fabric CA attribute. + # For example, the following converts an LDAP 'uid' attribute + # whose value begins with 'revoker' to a fabric CA attribute + # named "hf.Revoker" with a value of "true" (because the boolean expression + # evaluates to true). + # converters: + # - name: hf.Revoker + # value: attr("uid") =~ "revoker*" + converters: + - name: + value: + # The 'maps' section contains named maps which may be referenced by the 'map' + # function in the 'converters' section to map LDAP responses to arbitrary values. + # For example, assume a user has an LDAP attribute named 'member' which has multiple + # values which are each a distinguished name (i.e. a DN). For simplicity, assume the + # values of the 'member' attribute are 'dn1', 'dn2', and 'dn3'. + # Further assume the following configuration. + # converters: + # - name: hf.Registrar.Roles + # value: map(attr("member"),"groups") + # maps: + # groups: + # - name: dn1 + # value: peer + # - name: dn2 + # value: client + # The value of the user's 'hf.Registrar.Roles' attribute is then computed to be + # "peer,client,dn3". This is because the value of 'attr("member")' is + # "dn1,dn2,dn3", and the call to 'map' with a 2nd argument of + # "group" replaces "dn1" with "peer" and "dn2" with "client". + maps: + groups: + - name: + value: + +############################################################################# +# Affiliations section. Fabric CA server can be bootstrapped with the +# affiliations specified in this section. Affiliations are specified as maps. +# For example: +# businessunit1: +# department1: +# - team1 +# businessunit2: +# - department2 +# - department3 +# +# Affiliations are hierarchical in nature. In the above example, +# department1 (used as businessunit1.department1) is the child of businessunit1. +# team1 (used as businessunit1.department1.team1) is the child of department1. +# department2 (used as businessunit2.department2) and department3 (businessunit2.department3) +# are children of businessunit2. +# Note: Affiliations are case sensitive except for the non-leaf affiliations +# (like businessunit1, department1, businessunit2) that are specified in the configuration file, +# which are always stored in lower case. +############################################################################# +affiliations: + org1: + - department1 + - department2 + org2: + - department1 + +############################################################################# +# Signing section +# +# The "default" subsection is used to sign enrollment certificates; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +# +# The "ca" profile subsection is used to sign intermediate CA certificates; +# the default expiration ("expiry" field) is "43800h" which is 5 years in hours. +# Note that "isca" is true, meaning that it issues a CA certificate. +# A maxpathlen of 0 means that the intermediate CA cannot issue other +# intermediate CA certificates, though it can still issue end entity certificates. +# (See RFC 5280, section 4.2.1.9) +# +# The "tls" profile subsection is used to sign TLS certificate requests; +# the default expiration ("expiry" field) is "8760h", which is 1 year in hours. +############################################################################# +signing: + default: + authremote: {} + caconstraint: {} + expiry: 8760h + usage: + - signing + - key encipherment + - server auth + - client auth + - key agreement + profiles: null + +########################################################################### +# Certificate Signing Request (CSR) section. +# This controls the creation of the root CA certificate. +# The expiration for the root CA certificate is configured with the +# "ca.expiry" field below, whose default value is "131400h" which is +# 15 years in hours. +# The pathlength field is used to limit CA certificate hierarchy as described +# in section 4.2.1.9 of RFC 5280. +# Examples: +# 1) No pathlength value means no limit is requested. +# 2) pathlength == 1 means a limit of 1 is requested which is the default for +# a root CA. This means the root CA can issue intermediate CA certificates, +# but these intermediate CAs may not in turn issue other CA certificates +# though they can still issue end entity certificates. +# 3) pathlength == 0 means a limit of 0 is requested; +# this is the default for an intermediate CA, which means it can not issue +# CA certificates though it can still issue end entity certificates. +########################################################################### +csr: + cn: fabric-ca-server + keyrequest: + algo: ecdsa + size: 256 + names: + - C: US + ST: "North Carolina" + L: + O: Hyperledger + OU: Fabric + hosts: + - localhost + - 127.0.0.1 + - org2-tls-ca + - org2-tls-ca.test-network.svc.cluster.local + ca: + expiry: 131400h + pathlength: 1 + +########################################################################### +# Each CA can issue both X509 enrollment certificate as well as Idemix +# Credential. This section specifies configuration for the issuer component +# that is responsible for issuing Idemix credentials. +########################################################################### +idemix: + # Specifies pool size for revocation handles. A revocation handle is an unique identifier of an + # Idemix credential. The issuer will create a pool revocation handles of this specified size. When + # a credential is requested, issuer will get handle from the pool and assign it to the credential. + # Issuer will repopulate the pool with new handles when the last handle in the pool is used. + # A revocation handle and credential revocation information (CRI) are used to create non revocation proof + # by the prover to prove to the verifier that her credential is not revoked. + rhpoolsize: 1000 + + # The Idemix credential issuance is a two step process. First step is to get a nonce from the issuer + # and second step is send credential request that is constructed using the nonce to the isuser to + # request a credential. This configuration property specifies expiration for the nonces. By default is + # nonces expire after 15 seconds. The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration). + nonceexpiration: 15s + + # Specifies interval at which expired nonces are removed from datastore. Default value is 15 minutes. + # The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration) + noncesweepinterval: 15m + +############################################################################# +# BCCSP (BlockChain Crypto Service Provider) section is used to select which +# crypto library implementation to use +############################################################################# +bccsp: + default: SW + sw: + hash: SHA2 + security: 256 + filekeystore: + # The directory used for the software file-based keystore + keystore: msp/keystore + +############################################################################# +# Multi CA section +# +# Each Fabric CA server contains one CA by default. This section is used +# to configure multiple CAs in a single server. +# +# 1) --cacount +# Automatically generate non-default CAs. The names of these +# additional CAs are "ca1", "ca2", ... "caN", where "N" is +# This is particularly useful in a development environment to quickly set up +# multiple CAs. Note that, this config option is not applicable to intermediate CA server +# i.e., Fabric CA server that is started with intermediate.parentserver.url config +# option (-u command line option) +# +# 2) --cafiles +# For each CA config file in the list, generate a separate signing CA. Each CA +# config file in this list MAY contain all of the same elements as are found in +# the server config file except port, debug, and tls sections. +# +# Examples: +# fabric-ca-server start -b admin:adminpw --cacount 2 +# +# fabric-ca-server start -b admin:adminpw --cafiles ca/ca1/fabric-ca-server-config.yaml +# --cafiles ca/ca2/fabric-ca-server-config.yaml +# +############################################################################# + +cacount: + +cafiles: + +############################################################################# +# Intermediate CA section +# +# The relationship between servers and CAs is as follows: +# 1) A single server process may contain or function as one or more CAs. +# This is configured by the "Multi CA section" above. +# 2) Each CA is either a root CA or an intermediate CA. +# 3) Each intermediate CA has a parent CA which is either a root CA or another intermediate CA. +# +# This section pertains to configuration of #2 and #3. +# If the "intermediate.parentserver.url" property is set, +# then this is an intermediate CA with the specified parent +# CA. +# +# parentserver section +# url - The URL of the parent server +# caname - Name of the CA to enroll within the server +# +# enrollment section used to enroll intermediate CA with parent CA +# profile - Name of the signing profile to use in issuing the certificate +# label - Label to use in HSM operations +# +# tls section for secure socket connection +# certfiles - PEM-encoded list of trusted root certificate files +# client: +# certfile - PEM-encoded certificate file for when client authentication +# is enabled on server +# keyfile - PEM-encoded key file for when client authentication +# is enabled on server +############################################################################# +intermediate: + parentserver: + url: + caname: + + enrollment: + hosts: + profile: + label: + + tls: + certfiles: + client: + certfile: + keyfile: + +############################################################################# +# CA configuration section +# +# Configure the number of incorrect password attempts are allowed for +# identities. By default, the value of 'passwordattempts' is 10, which +# means that 10 incorrect password attempts can be made before an identity get +# locked out. +############################################################################# +cfg: + identities: + passwordattempts: 10 + +############################################################################### +# +# Operations section +# +############################################################################### +operations: + # host and port for the operations server + listenAddress: 127.0.0.1:9444 + + # TLS configuration for the operations endpoint + tls: + # TLS enabled + enabled: false + + # path to PEM encoded server certificate for the operations server + cert: + file: + + # path to PEM encoded server key for the operations server + key: + file: + + # require client certificate authentication to access all resources + clientAuthRequired: false + + # paths to PEM encoded ca certificates to trust for client authentication + clientRootCAs: + files: [] + +############################################################################### +# +# Metrics section +# +############################################################################### +metrics: + # statsd, prometheus, or disabled + provider: disabled + + # statsd configuration + statsd: + # network type: tcp or udp + network: udp + + # statsd server address + address: 127.0.0.1:8125 + + # the interval at which locally cached counters and gauges are pushsed + # to statsd; timings are pushed immediately + writeInterval: 10s + + # prefix is prepended to all emitted statsd merics + prefix: server diff --git a/test-network-k8s/docs/APPLICATIONS.md b/test-network-k8s/docs/APPLICATIONS.md new file mode 100644 index 00000000..2758f463 --- /dev/null +++ b/test-network-k8s/docs/APPLICATIONS.md @@ -0,0 +1,106 @@ +# Working with Applications + +## TL/DR: + +```shell +$ ./network rest-easy +Launching fabric-rest-sample application: +✅ - Ensuring fabric-rest-sample image ... +✅ - Constructing fabric-rest-sample connection profiles ... +✅ - Starting fabric-rest-sample ... + +The fabric-rest-sample has started. See https://github.com/hyperledgendary/fabric-rest-sample/tree/main/asset-transfer-basic/rest-api-typescript#rest-api for additional usage. +To access the endpoint: + +export SAMPLE_APIKEY=97834158-3224-4CE7-95F9-A148C886653E +curl -s --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost/api/assets + +🏁 - Fabric REST sample is ready. +``` + +```shell +$ export SAMPLE_APIKEY=97834158-3224-4CE7-95F9-A148C886653E + +$ ./network chaincode invoke '{"Args":["CreateAsset","1","blue","35","tom","1000"]}' + +$ curl -s --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost/api/assets | jq +[ + { + "Key": "1", + "Record": { + "ID": "1", + "color": "blue", + "size": 35, + "owner": "tom", + "appraisedValue": 1000 + } + } +] + +$ open https://github.com/hyperledgendary/fabric-rest-sample/tree/main/asset-transfer-basic/rest-api-typescript#rest-api +``` + +## Guide for Gateway Client Applications + +TODO: this section is a work-in-progress. + +### EXTERNAL Gateway Client (localhost) + +For certain development scenarios, it is advantageous to run a Gateway Client externally, using a bridge +or port forward to access services running behind the veil of Kubernetes networking. For instance, during active +development we can run a Gateway Client under the microscope of an IDE / debugger, on a local system, connected +to a remote network as if it were running resident within the Kube. As the system is developed (bugs addressed, etc.), +the application author can transition the updated routines into Docker containers, verify locally, and push +into the container registry for validation within the Kubernetes network. + +Here is a brief overview of the steps necessary to run EXTERNAL gateway applications: + +1. Open a TCP port forward from the local host to a targeted peer: +```shell +kubectl -n test-network port-forward svc/org1-peer1 7051:7051 +``` + +2. Add "mock DNS" records to /etc/hosts for TLS host validation: +```shell +127.0.0.1 org1-peer1 +``` + +3. Configure the gateway client to connect to `org1-peer1:7051`, or the kube TCP port forward. + + +4. Launch the gateway client application locally, e.g. in a docker container or attached to an IDE. + + +5. Update this guide with feedback, recipes, and stories of successful client development on Kube/KIND. + + +### INTERNAL Gateway Client (In Kube) + +#### TODO: Deploy + +```shell +./network application ACTION +``` + + +#### Local Container Registry + +Docker images built locally can be uploaded to the `localhost:5000` container registry for +immediate access within the Kube/KIND cluster. In addition to providing fast turn-around to/from containers +running in Kube, the use of a private container registry allows us to quickly iterate on code without uploading +images to the Internet. Even when using _private_ container registries, the use of a local server saves valuable +time when loading images into the kind control plane. + +e.g.: +```shell +docker build -t localhost:5000/my-gateway-app . +docker push localhost:5000/my-gateway-app +``` + +Provided that the `imagePullPolicy` for the client deployment is not set to `IfNotPresent`, killing the current pod +running the gateway client will force a refresh with the latest image layer available at the local registry. + + +#### Aggregating MSP and Certificates + +#### Deploying to the Namespace \ No newline at end of file diff --git a/test-network-k8s/docs/CA.md b/test-network-k8s/docs/CA.md new file mode 100644 index 00000000..c8758b24 --- /dev/null +++ b/test-network-k8s/docs/CA.md @@ -0,0 +1,281 @@ +# Certificate Authorities + +This guide serves as a companion to the [Fabric CA Deployment Guide](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/ca-deploy.html), +the definitive reference for planning, configuring, and managing CAs within a production Hyperledger Fabric installation. + +For individual fabric nodes to communicate securely over a network, all interactions are performed over secure sockets +with (at a minimum) server side TLS certificate verification. In addition, for the individual participants of a Fabric +network to interact with the blockchain, the participant identities and activities are verified against an Enrollment +Certificate or 'ECert' authority. + +In this document we'll outline the key aspects of bootstrapping test network TLS and ECert CAs, registration and +enrollment of node identities, and address some effective strategies for storage and organization of channel and +node local MSP data structures. + + +### TL/DR : +```shell +$ ./network up + +Launching network "test-network": +... +✅ - Launching TLS CAs ... +✅ - Enrolling bootstrap TLS CA users ... + +✅ - Registering and enrolling ECert CA bootstrap users ... +✅ - Launching ECert CAs ... +✅ - Enrolling bootstrap ECert CA users ... +... +🏁 - Network is ready. +``` + + +## [Planning for a CA](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/ca-deploy-topology.html#planning-for-a-ca) + +Setting up a CA framework is one of the more daunting aspects of a Fabric installation. There is an incredible amount +of flexibility possible with the Fabric CA architecture, so to keep things straightforward we have opted to aim for a +simplified, but realistic CA deployment illustrating the key touch points with Kubernetes: + +- Each organization maintains distinct, [independent volumes](../kube/pv-fabric-org0.yaml) for the storage of MSP and + TLS certificates. This forces the consortium organizer to plan for the distribution of _public_ certificates to + member organizations, while maintaining an independent, secret storage location for _private_ signing keys. + + +- Each organization maintains two distinct, separate CA instances : one dedicated to [TLS](../kube/org0/org0-tls-ca.yaml) + Certificate Signing Requests, and a second process dedicated to [ECert](../kube/org0/org0-ecert-ca.yaml) Enrollments + and identity MSPs. + + +- Certificate organization and [Folder Structure](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/use_CA.html#folder-structure-for-your-org-and-node-admin-identities) + strictly adheres to the best practices and guidelines recommended by the CA Deployment Guide. + + +- The `cryptogen` anti-pattern is **strictly forbidden**. All TLS and MSP enrollments are constructed using the CA + registration and enrollment REST services, coordinated by calls to `fabric-ca-client` running directly on the + CA pods. When working with certificates, the fabric CA client ONLY has visibility to the organization's local volume + storage. + + +- TLS CA configuration and certificates are maintained in each org's persistent volume at `/var/hyperledger/fabric-tls-ca-server` + + +- ECert CA configuration and certificates are maintained in each org's persistent volume at `/var/hyperledger/fabric-ca-server` + + +- fabric-ca-client configuration and certificates are maintained in each org's persistent volume at `/var/hyperledger/fabric-ca-client` + + +- ECert and MSP data structures are maintained in each org's persistent volume at `/var/hyperledger/fabric/organizations` + + + +### Future Enhancements: + +- **_Bring your own Certificates_** : It would be nice to boostrap the network using a single, top-level signing authority, + rather than generating self-signed certificates when the system is bootstrapped. Ideally this will be realized by + introducing an [Intermediate CA](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/ca-deploy-topology.html#when-would-i-want-an-intermediate-ca) + and/or alternate signing chains backed by formal (e.g. letsencrypt, Thawte, Verisign, etc.) certificate authorities. + + +- **_Dual Headed CAs_** : In practice, juggling two distinct deployments between TLS and ECert servers adds little + functional value. It would be nice to simplify the configuration, deployment, and bootstrapping scripts such that + each org manages a single, dual-headed CA capable of responding to both TLS as well as ECert enrollmnent rerquests. + + +- **_Time-Bomb Certificates_** : By default the certificates issued by the test network are valid for 1 (one) year. For + lightweight or adhoc testing, this is fine. But when applied to production deployments, certificate expiry is a + real operational challenge. For instance, it is possible to soft-lock a Fabric network when all system certificates + expire _en-masse_ - it's impossible to re-establish a consensus and renew the certificates! + + +- **_Mutual TLS_** : Server-side TLS is a minimum, but the addition of client-side TLS certificates will help fully + secure all TCP channels within the Fabric network. + + +- **_Bugs_** : `./network up` currently goes through the process of bootstrapping a fabric network from scratch, but + does not handle "multiple runs" or the complete course of errors that can occur in the wild. For instance, If the + routine is run multiple times in succession, it will overwrite the network's certificate chains and soft-lock the + network. + + +## [Process Overview](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#) + +The [sequence of activities](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#what-order-should-i-deploy-the-cas) +necessary to bring up a CA infrastructure is well documented by the CA Deployment Guide: + +1. [Deploy the TLS CAs](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#deploy-the-tls-ca) + 1. [Configure the TLS CA Servers](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#modify-the-tls-ca-server-configuration) + 1. [Launch the TLS CA Servers](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#start-the-tls-ca-server) + 1. [Enroll the TLS CA Bootstrap Admin Users](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#enroll-bootstrap-user-with-tls-ca) + +1. [Deploy the Organization CA](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#deploy-an-organization-ca) + 1. [Register and enroll the org CA bootstrap identity with the TLS CA](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#register-and-enroll-the-organization-ca-bootstrap-identity-with-the-tls-ca) + 1. [Configure the ECert CA Servers](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#modify-the-ca-server-configuration) + 1. [Launch the ECert CA Servers](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#start-the-ca-server) + 1. [Enroll the ECert CA Bootstrap / Admin User](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#enroll-the-ca-admin) + + +## [Deploy the TLS CAs](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#deploy-the-tls-ca) + +### [Configure the TLS CA Servers](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#modify-the-tls-ca-server-configuration) + +While the CA guide suggests running the `fabric-ca-server` binary to generate a default configuration file, for the +test network we've skipped this step and have added a [config/fabric-tls-ca-server-config.yaml](../config/org0/fabric-tls-ca-server-config.yaml) +to the top level of this project. + +Changes have been made to reflect: + +- `port: 443` binds all traffic to the default HTTPS port +- `tls.enabled: true` enables TLS for registration and enrollment requests +- `ca.name: ` matches the Kubernetes `Service` host alias +- `csr.hosts:` includes host aliases for accessing the CA with Kube DNS + + +Prior to launching the CA, for each org we create a configmap including the TLS CA server yaml: + +```shell +kubectl -n test-network create configmap org0-config --from-file=config/org0 +kubectl -n test-network create configmap org1-config --from-file=config/org1 +kubectl -n test-network create configmap org2-config --from-file=config/org2 +``` + + +### [Launch the TLS CA Servers](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#start-the-tls-ca-server) + +```shell +✅ - Launching TLS CAs ... +``` + +For each org we create a Kube Deployment and Service, ensuring that the org config +map and persistent volume maps to the correct location on disk. + +```shell +kubectl -n test-network apply -f kube/org0/org0-tls-ca.yaml +kubectl -n test-network apply -f kube/org1/org1-tls-ca.yaml +kubectl -n test-network apply -f kube/org2/org2-tls-ca.yaml +``` + +As a side-effect of bootstrapping the TLS CA, each storage volume will include a self-signed certificate +pair to serve as the **Root TLS Certificate**. Pay special attention to this path, as it will be used extensively +to verify the TLS host name of all services within the organization: +```shell +${FABRIC_CA_CLIENT_HOME}/tls-root-cert/tls-ca-cert.pem +``` + + +### [Enroll the TLS CA Bootstrap Admin Users](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#enroll-bootstrap-user-with-tls-ca) +```shell +✅ - Enrolling bootstrap TLS CA users ... +``` + +After the TLS server is running, we need to enroll the bootstrap admin user with the CA. This admin user will +then be employed to fulfill a Certificate Signing request for the ECert CA servers, allowing for full host +verification when connecting to the ECert CAs via https. + +To enroll the bootstrap TLS CA users, each org runs within the TLS CA pod: +```shell + fabric-ca-client enroll \ + --url https://'$auth'@'${tlsca}' \ + --tls.certfiles $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem \ + --csr.hosts '${tlsca}' \ + --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp +``` + +The --mspdir output of this command is a set of certificates for use with the ECert CA. This enrollment MSP +will be used to register and enroll the ECert bootstrap user. + + +## [Deploy the Organization CA](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#deploy-an-organization-ca) + +The organization (ECert) CA is used to issue MSP certificates for nodes, channels, and identities in the fabric network. +Before we can set up the peers, orderers, and channels, we will need to bootstrap an ECert CA administrator +for each org in the network. + + +### [Register and enroll the organization CA bootstrap identity with the TLS CA](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#register-and-enroll-the-organization-ca-bootstrap-identity-with-the-tls-ca) +```shell +✅ - Registering and enrolling ECert CA bootstrap users ... +``` + +The TLS CA can be used to fulfill a Certificate Signing Request on behalf of each organization's ECert CA. + +```shell + fabric-ca-client register \ + --id.name rcaadmin \ + --id.secret rcaadminpw \ + --url https://'${tlsca}' \ + --tls.certfiles $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem \ + --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + + fabric-ca-client enroll \ + --url https://'${tlsauth}'@'${tlsca}' \ + --tls.certfiles $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem \ + --csr.hosts '${ecertca}' \ + --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/rcaadmin/msp +``` + +**Important**: The output from this enrollment includes the ECert CA's public certificate and private signing keys. +When the ECert CA pod is launched, the server configuration references the `tls.certfile` and `tls.keyfile` attributes +by specifying `FABRIC_CA_SERVER_TLS_CERTFILE` and `FABRIC_CA_SERVER_TLS_KEYFILE` environment in the pod's environment. + + +### [Configure the ECert CA Servers](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#modify-the-ca-server-configuration) + +When launching the ECert CA pods, both the org volume shares and org config maps are made available via volume shares. +The [fabric-ecert-ca-server.yaml](../config/org0/fabric-ecert-ca-server-config.yaml) includes overrides for: + +- `port: 443` binds all traffic to the default HTTPS port +- `tls.enabled: true` enables TLS for registration and enrollment requests +- `ca.name: ` matches the Kubernetes `Service` host alias +- `csr.hosts:` includes host aliases for accessing the CA with Kube DNS + +In addition, pay special attention to the location of the `FABRIC_CA_SERVER_TLS_CERTFILE` and `FABRIC_CA_SERVER_TLS_KEYFILE` +environment variables in the [ECert deployment descriptor](../kube/org0/org0-ecert-ca.yaml). These variables +reference the TLS certificate authority and signing keys as generated by the admin bootstrap enrollment. + + +### [Launch the ECert CA Servers](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#start-the-ca-server) +```shell +✅ - Launching ECert CAs ... +``` + +```shell +kubectl -n test-network apply -f kube/org0/org0-ecert-ca.yaml +kubectl -n test-network apply -f kube/org1/org1-ecert-ca.yaml +kubectl -n test-network apply -f kube/org2/org2-ecert-ca.yaml +``` +- [x] Note: The `rcaadmin` enrollment's `cert.pem` and `key.pem` locations are specified in the ecert CA's k8s deployment as environment variables. + + +### [Enroll the ECert CA Bootstrap / Admin User](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#enroll-the-ca-admin) +```shell +✅ - Enrolling bootstrap ECert CA users ... +``` + +Finally, after the services are active, we can connect to each organization's ECert CA using TLS and +activate the `rcaadmin` (Root Certificate Authority) admin user. This user will be employed to generate the +local MSP certificate structure for all of the nodes in our test network. + +```shell + fabric-ca-client enroll \ + --url https://'${auth}'@'${ecert_ca}' \ + --tls.certfiles $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem \ + --mspdir $FABRIC_CA_CLIENT_HOME/'${ecert_ca}'/rcaadmin/msp +``` + + +## Next Steps : + +After the CAs have been deployed, each org in the Kube namespace includes: + +- One TLS CA `Service`, forwarding internal traffic from https://orgN-tls-ca to the TLS CA +- One TLS CA `Deployment` +- One TLS CA `Pod` +- One ECert CA `Service`, forwarding internal traffic from https://orgN-ecert-ca to the ECert CA +- One ECert CA `Deployment` +- One ECert CA `Pod` +- One TLS CA admin bootstrap user `tlsadmin` enrollment and TLS root certificate. +- One ECert CA admin bootstrap user `rcaadmin` enrollment and MSP root certificate. + + +### [Launch the Test Network...](TEST_NETWORK.md) diff --git a/test-network-k8s/docs/CHAINCODE.md b/test-network-k8s/docs/CHAINCODE.md new file mode 100644 index 00000000..e967d882 --- /dev/null +++ b/test-network-k8s/docs/CHAINCODE.md @@ -0,0 +1,278 @@ +# 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 : +```shell +$ ./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. +``` + +```shell +$ ./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](link) +pattern, relying on an embedded [External Builder](link) 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](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html#writing-chaincode-to-run-as-an-external-service). + +- 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 +```shell +✅ - 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. `kubectl cp` the chaincode archive from the local file system to the organization's persistent volume storage. + + +3. Install the chaincode archive on a peer in the organization: +```shell + export CORE_PEER_ADDRESS='${org}'-peer1:7051 + peer lifecycle chaincode install chaincode/asset-transfer-basic.tgz +``` + + +4. 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. + + +5. The chaincode docker [image is launched](../kube/org1/org1-cc-asset-transfer-basic.yaml) 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`. + + +6. Finally, the Admin CLI issues a series of peer commands to approve and commit the chaincode for the org: + +```shell + 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 +```shell +$ ./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 +```shell +$ ./network chaincode query '{"Args":["ReadAsset","1"]}' | jq +{ + "ID": "1", + "color": "blue", + "size": 35, + "owner": "tom", + "appraisedValue": 1000 +} +``` + +### Describe +```shell +$ ./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](../../asset-transfer-basic/chaincode-external) +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](../../asset-transfer-basic/chaincode-external/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.: +```java + fmt.Printf("reading asset %s\n", id) +``` + +2. Build the docker image locally with: +```shell +docker build -t asset-transfer-basic ../asset-transfer-basic/chaincode-external +``` + +3. Override the test network's default chaincode image, pointing to our local container registry: +```shell +export TEST_NETWORK_CHAINCODE_IMAGE=localhost:5000/asset-transfer-basic +``` + +3. Publish the custom image to the local registry: + +```shell +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, we can simply connect to a native binary running in a debugger, an IDE, or docker image +running locally! + +Using a singular framework, we can employ this method to enable _rapid_ **edit/test/debug cycles** when authoring +code, **verify** docker images generated by a CI/CD pipeline, and run integration tests on a local Kubernetes. + +For example, we can deploy the basic asset transfer smart contract with a [connection.json](../chaincode/asset-transfer-basic-debug/connection.json) +referencing a service bound to the Docker network's IP address for the local host: +```json +{ + "address": "host.docker.internal:9999", +} +``` +When the test network opens a TCP socket to the chaincode process, the connection will be made from containers +running within Kubernetes to the port opened on the local system. Let's employ this to technique by running a +chaincode endpoint in a local Docker container, native binary, or IDE debugger: + + +0. Edit assetTransfer.go and [Build the Chaincode Image](#build-a-chaincode-docker-image) + + +1. Bring up the test network with: +```shell +$ ./network up +$ ./network channel create +``` + +2. Install the debug chaincode archive, using a connection to localhost:9999 : +```shell +$ export TEST_NETWORK_CHAINCODE_NAME=asset-transfer-basic-debug +$ export TEST_NETWORK_CHAINCODE_IMAGE=localhost:5000/asset-transfer-basic + +$ ./network chaincode install +Installing chaincode "asset-transfer-basic-debug": +✅ - Packaging chaincode folder chaincode/asset-transfer-basic-debug ... +✅ - Transferring chaincode archive to org1 ... +✅ - Installing chaincode for org org1 ... +🏁 - Chaincode is installed with CHAINCODE_ID=basic_1.0:159ed2f227586f40c5804e157919903fda2b861488f35eefb365eb9d85a73da3 +``` + +3. Set the `CHAINCODE_ID` and launch the chaincode binding to localhost:9999: +```shell +$ export CHAINCODE_ID=basic_1.0:159ed2f227586f40c5804e157919903fda2b861488f35eefb365eb9d85a73da3 + +$ docker run \ + --rm \ + --name asset-transfer-basic-debug \ + -e CHAINCODE_ID \ + -e CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999 \ + -p 9999:9999 \ + localhost:5000/asset-transfer-basic +``` + +4. Activate the chaincode (commit and approve on the peer): +```shell +$ ./network chaincode activate +``` + +When the peer communicates with chaincode in this fashion, the network will reach out to the grpc server +bound to the localhost:9999, rather than connecting to services locked up behind the wall of Kubernetes +networking. + +As an exercise, try using this approach to: + +- introduce some `fmt.Printf` logging output to the chaincode, attaching to a process running locally in an IDE / debugger. +- build your local modifications into a docker container, publishing locally to localhost:5000/asset-transfer-basic +- test your local modifications by running a chaincode referencing the image hosted in the local container registry. + + +## Next Steps: + +[Writing a Blockchain Application](APPLICATIONS.md) \ No newline at end of file diff --git a/test-network-k8s/docs/CHANNELS.md b/test-network-k8s/docs/CHANNELS.md new file mode 100644 index 00000000..23fa33f6 --- /dev/null +++ b/test-network-k8s/docs/CHANNELS.md @@ -0,0 +1,206 @@ +# Channels + +Once the test network peers and orderers have been started, and the network identities have been registered +and enrolled with the ECert CA, we can construct a channel linking the participants of the test network +blockchain. + +## TL/DR : + +```shell +$ export TEST_NETWORK_CHANNEL_NAME="mychannel" + +$ ./network channel create +Creating channel "mychannel": +✅ - Creating channel MSP ... +✅ - Aggregating channel MSP ... +✅ - Launching admin CLIs ... +✅ - Creating channel "mychannel" ... +✅ - Joining org1 peers to channel "mychannel" ... +✅ - Joining org2 peers to channel "mychannel" ... +🏁 - Channel is ready. +``` + +## Process Overview + +In order to construct a communication channel, the following steps must be performed: + +1. TLS and MSP public certificates must be aggregated and distributed to all participants in the network. + +2. Each organization will launch a command-line pod with the MSP environment such that all fabric binaries are + executed as the Admin user. + +3. The channel genesis block is constructed from `configtx.yaml`, and `osnadmin` is used to distribute the new + channel configuration block to all orderers in the network. + +4. The network peers fetch the genesis block from the orderers, and use the configuration to join the channel. + + +## Distributing Channel MSP +```shell +✅ - Creating channel MSP ... +✅ - Aggregating channel MSP ... +``` + +One of the responsibilities of a Hyperledger Fabric _Consortium Organizer_ is to distribute the public MSP and +TLS certificates to organizations participating in a blockchain. In the Docker composed based test network, or +systems bootstrapped with the `cryptogen` command, all of the public certificates will be available on a common +file system or volume share. In our Kubernetes test network, each organization maintains the cryptographic +assets on a distinct persistent volume, invisible to other the other participants in the network. + +To distribute the TLS and MSP _public_ certificates, the test network emulates the responsibilities of the +consortium organizer by constructing a [Channel MSP](https://hyperledger-fabric.readthedocs.io/en/latest/membership/membership.html#channel-msps) +structure, extracting the relevant certificate files into a single `msp-{org}.tar.gz` archive. This MSP +archive is then relayed to network participants, where it can be extracted and used to set the MSP context +in which the peer executes administrative commands. + +The kube-specific techniques employed in MSP [construction](link) and [distribution](link) are: + +- Channel MSP is generated by piping shell commands into each org's ECert CA pod. +- Channel MSP is extracted to the local system by piping the output of `tar` through `kubectl` (equivalent + to the [kubectl cp command](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#cp)). + MSP archives are saved locally in `/build/msp-{org}.tar.gz` archives. +- Channel MSP is distributed across network participants by transferring the MSP archive files from + `build/msp/msp-{org}.tgz` into the cluster as a config map. +- An `initContainer` is launched in each organization's Admin CLI pod, unfurling the MSP context from the + `msp-config` config map into the local volume. + +Despite this additional complexity, this technique allows us to carefully target the MSP context in which +remote peer commands execute. The construct of an _MSP Archive_ may be extended to other circumstances +in which a consortium organizer transfers the _public_ certificates in an out-of-band fashion to +participants of a blockchain network. + +Aggregating the certificates as a local MSP archive is accomplished by piping a `tar` archive from the output +of a remote `kubectl` into a local archive files. These files are then mounted into the Kube namespace by +constructing the `msp-config` config map: + +```shell +kubectl -n $NS exec deploy/org0-ecert-ca -- tar zcvf - -C /var/hyperledger/fabric organizations/ordererOrganizations/org0.example.com/msp > msp/msp-org0.example.com.tgz +kubectl -n $NS exec deploy/org1-ecert-ca -- tar zcvf - -C /var/hyperledger/fabric organizations/peerOrganizations/org1.example.com/msp > msp/msp-org1.example.com.tgz +kubectl -n $NS exec deploy/org2-ecert-ca -- tar zcvf - -C /var/hyperledger/fabric organizations/peerOrganizations/org2.example.com/msp > msp/msp-org2.example.com.tgz + +kubectl -n $NS delete configmap msp-config || true +kubectl -n $NS create configmap msp-config --from-file=msp/``` +``` + + +## `Admin` Commands +```shell +✅ - Launching admin CLIs ... +``` + +After the channel MSP archives have been constructed and loaded into the `msp-config` ConfigMap, a series +of kubernetes pods are launched in the namespace with an environment suitable for running the Fabric +`peer` commands as the organization Administrator. Before starting the CLI admin container, an `initContainer` +reads the MSP archives and unfurls them into a location on the org's persistent volume: + +```yaml +# This init container will unfurl all of the MSP archives listed in the msp-config config map. +initContainers: +- name: msp-unfurl + image: busybox + command: + - sh + - -c + - "for msp in $(ls /msp/msp-*.tgz); do echo $msp && tar zxvf $msp -C /var/hyperledger/fabric; done" + volumeMounts: + - name: msp-config + mountPath: /msp + - name: fabric-volume + mountPath: /var/hyperledger +``` + +Once the MSP archives are extracted, the CLI is launched and the environment set such that `peer` commands +will be executed with the organization's Administrative role. + +```shell +cat kube/org0/org0-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - +cat kube/org1/org1-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - +cat kube/org2/org2-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - +``` + +## Create the Channel +```shell +✅ - Creating channel "mychannel" ... +``` + +As the _consortium leader_ org0, we create the channel's genesis block and use the orderer admin REST +services to register the channel genesis block configuration on the ordering nodes: + +```shell +configtxgen -profile TwoOrgsApplicationGenesis -channelID '${CHANNEL_NAME}' -outputBlock genesis_block.pb + +osnadmin channel join --orderer-address org0-orderer1:9443 --channelID '${CHANNEL_NAME}' --config-block genesis_block.pb +osnadmin channel join --orderer-address org0-orderer2:9443 --channelID '${CHANNEL_NAME}' --config-block genesis_block.pb +osnadmin channel join --orderer-address org0-orderer3:9443 --channelID '${CHANNEL_NAME}' --config-block genesis_block.pb +``` + + +## Join Peers + +```shell +✅ - Joining org1 peers to channel "mychannel" ... +✅ - Joining org2 peers to channel "mychannel" ... +``` + +After the channel configurations have been registered with the network orderers, we will join the peers to the channel +by retrieving the genesis block from the orderers and then joining the channel: + +```shell + # Fetch the genesis block from an orderer + peer channel \ + fetch oldest \ + genesis_block.pb \ + -c '${CHANNEL_NAME}' \ + -o org0-orderer1:6050 \ + --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem + + # Join peer1 to the channel. + CORE_PEER_ADDRESS='${org}'-peer1:7051 \ + peer channel \ + join \ + -b genesis_block.pb \ + -o org0-orderer1:6050 \ + --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem + + # Join peer2 to the channel. + CORE_PEER_ADDRESS='${org}'-peer2:7051 \ + peer channel \ + join \ + -b genesis_block.pb \ + -o org0-orderer1:6050 \ + --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem +``` + + +## Set Anchor Peers (Optional) +```shell +$ ./network anchor peer2 +✅ - Updating anchor peers to "peer2" ... +``` + +In the test network, the configtx.yaml sets the organization [Anchor Peers](https://hyperledger-fabric.readthedocs.io/en/latest/glossary.html?highlight=anchor#anchor-peer) +to "peer1" in the genesis block. As such, no additional configuration is necessary for neighboring +organizations to discover additional peers in the network. + +However, the process of setting the anchor peers on a channel requires a more complicated scripting process, so we +have included in the test network a mechanism to illustrate how anchor peers may be set on a network after a +channel has been constructed. + +Up to this point in the network configuration, the shell scripts orchestrating the remote volumes, peers, and +admin commands have all been executed by piping a sequence of commands into an existing pod directly +into the input of a `kubectl` command. For small command sets this is adequate, but for the more complicated +process of registering a channel anchor peer, we have elected to use a different approach to launch the peer +update scripts on the kubernetes cluster. + +When updating anchor peers, the `./network` script will: + +1. Transfer the shell scripts from `/scripts/*.sh` into the remote organization's persistent volume. +2. Issue a `kubectl exec -c "script-name.sh {args}"` on the org's admin CLI pod. + +For non-trivial Fabric administative tasks, this approach of uploading a script into the cluster and then +executing in an admin pod works well. + + +## Next Steps + +### [Working with Chaincode](CHAINCODE.md) \ No newline at end of file diff --git a/test-network-k8s/docs/KUBERNETES.md b/test-network-k8s/docs/KUBERNETES.md new file mode 100644 index 00000000..6472e1cf --- /dev/null +++ b/test-network-k8s/docs/KUBERNETES.md @@ -0,0 +1,161 @@ +# Kubernetes + +To get started with the Kube test network, you will need access to a Kubernetes cluster. + +## TL/DR : + +```shell +$ ./network kind +Initializing KIND cluster "kind": +✅ - Pulling docker images for Fabric 2.3.2 ... +✅ - Creating cluster "kind" ... +✅ - Launching Nginx ingress controller ... +✅ - Launching container registry "kind-registry" at localhost:5000 ... +🏁 - Cluster is ready. +``` + +and : +```shell +$ ./network unkind +Deleting cluster "kind": +☠️ - Deleting KIND cluster kind ... +🏁 - Cluster is gone. +``` + + +## Kube Context: + +For illustration purposes, this project attempts in all cases to _keep it simple_ as the +general rule. By default, we will rely on `kind` ([Kubernetes IN Docker](https://kind.sigs.k8s.io)) +as a mechanism to quickly spin up ephemeral, short-lived clusters for development and +illustration. + +To maximize portability across revisions, vendor distributions, hardware profiles, and +network topologies, this project relies _exclusively_ on scripted interaction with the +Kube API controller to reflect updates in a remote cluster. While this may not be the +ideal technique for managing production workloads, the objective of this guide is to provide +clarity on the nuances of Fabric / Kubernetes deployments, rather than an opinionated +perspective on state of the art techniques for cloud Dev/Ops. Targeting +the core Kube APIs means that there is a good chance that the systems will work "as-is" +simply by setting the kubectl context to reference a cloud-native cluster (e.g. OCP, IKS, +AWS, etc.) + +If you don't have access to an existing cluster, or want to set up a short-lived cluster +for development, testing, or CI, you can create a new cluster with: + +```shell +$ ./network kind +``` +or: +```shell +$ kind create cluster +``` + +By default, `kind` will set the current Kube context to reference the new cluster. Any +interaction with `kubectl` (or kube-context aware SDKs) will inherit the current context. + +```shell +$ kubectl cluster-info +Kubernetes control plane is running at https://127.0.0.1:55346 +CoreDNS is running at https://127.0.0.1:55346/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy + +To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. +``` + +When you are done with the cluster, tear it down with: +```shell +$ ./network unkind +``` +or: +```shell +$ kind delete cluster +``` + +## Test Network Structure + +To emulate a more realistic example of multi-party collaboration, the test network +forms a blockchain consensus group spanning three virtual organizations. Access to the +blockchain is entirely constrained to Kubernetes private networks, and consuming applications +make use of a Kube ingress controller for external visibility. + +In k8s terms: + +- The blockchain is contained within a single Kubernetes `Cluster`. +- Blockchain services (nodes, orderers, chaincode, etc.) reside within a single `Namespace`. +- Each organization maintains a distinct, independent `PersistentVolumeClaim` for TLS certificates, + local MSP, private data, and transaction ledgers. +- Smart Contracts rely exclusively on the [Chaincode-as-a-Service](link) and [External Builder](link) + patterns, running in the cluster as Kube `Deployments` with companion `Services`. +- An HTTP(s) `Ingress` and companion gateway application is required for external access to the blockchain. + +When running the test network locally, the `./network kind` bootstrap will configure the system with +an [Nginx ingress controller](link), a private [Container Registry](link), and persistent volumes / claims for +host-local organization storage. + +Behind the scenes, `./network kind` is running: + +```shell +# Create the KIND cluster and nginx ingress controller bound to :80 and :443 +kind create cluster --name ${TEST_NETWORK_CLUSTER_NAME:-kind} --config scripts/kind-config.yaml + +# Create the Kube namespace +kubectl create namespace ${TEST_NETWORK_NAMESPACE:-test-network} + +# Create host persistent volumes (tied the kind-control-plane docker image lifetime) +kubectl create -f kube/pv-fabric-org0.yaml +kubectl create -f kube/pv-fabric-org1.yaml +kubectl create -f kube/pv-fabric-org2.yaml + +# Create persistent volume claims binding to the host (docker) volumes +kubectl -n $NS create -f kube/pvc-fabric-org0.yaml +kubectl -n $NS create -f kube/pvc-fabric-org1.yaml +kubectl -n $NS create -f kube/pvc-fabric-org2.yaml +``` + +## Container Registry + +The [kube yaml descriptors](../kube) generally rely on the public Fabric images maintained at the public +Docker and GitHub container registries. For casual usage, the test network will bootstrap and launch CAs, +peers, orderers, chaincode, and sample applications without any additional configuration. + +While public images are made available for pre-canned samples, there will undoubtedly be cases +where you would like to build custom chaincode, gateway client applications, or custom builds of core +Fabric binaries without uploading your code to a public registry. For this purpose, the Kube test +network includes a [Local Registry](https://kind.sigs.k8s.io/docs/user/local-registry/) available for +you to _quickly_ deploy custom images directly into the cluster without uploading your code to the +Internet. + +By default, the [kind.sh](../scripts/kind.sh) bootstrap will configure and link up a local container +registry running at `localhost:5000/`. Images pushed to this registry will be immediately available +to Pods deployed to the local cluster. + +For dev/test/CI based flows using an external registry, the traditional Kubernetes practice of +[Adding ImagePullSecrets to a service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account) +still applies. + + +## Cloud Vendors + +While the test network primarily targets KIND clusters, the singular reliance on the Kube API plane +means that it should also work without modification on any modern cloud-based or bare metal +Kubernetes distribution. While supporting the entire ecosystem of cloud vendors is not in scope +for this sample project, we'd love to hear feedback, success stories, or bugs related to applying the +test network to additional platforms. + +In general, at a high-level the steps required to port the test network to ANY kube vendor are: + +- Configure an HTTP `Ingress` for access to any gateway, REST, or companion blockchain applications. +- Register `PersistentVolumeClaims` for each of the organizations in the test network. +- Create a `Namespace` for each instance of the test network. +- Upload your chaincode, gateway clients, and application logic to an external Container Registry. +- Run with a `ServiceAccount` and role bindings suitable for creating `Pods`, `Deployments`, and `Services`. + +Example configurations for common cloud vendors: + +### IKS +### OCP +### AWS +### Azure + +## Next : [Fabric Certificate Authorities](CA.md) + diff --git a/test-network-k8s/docs/README.md b/test-network-k8s/docs/README.md new file mode 100644 index 00000000..9319e8f8 --- /dev/null +++ b/test-network-k8s/docs/README.md @@ -0,0 +1,49 @@ +# Kubernetes Test Network + +Starting in release 2.0, Hyperledger introduced the [test-network](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html) +to serve as both an accelerator and learning resource for running Fabric networks. In addition to +providing a study guide for operational patterns, the test-network provided a baseline environment for members of +the Fabric community to quickly get up to speed with a working, local system, author smart contracts, and develop +simple blockchain applications. + +While test-network provided a solid foundation for casual Fabric development, the over-reliance on +[Docker Compose](https://docs.docker.com/compose/) introduced tremendous, non-trivial complexity when transitioning +applications to production. Without belaboring the many issues and anti-patterns present in the Compose-based +test network, we'll submit that the best path forward is to _align_ the development and production patterns around a +common orchestration framework - Kubernetes. + +Similar to Fabric, Kubernetes introduces a steep learning curve and presents a dizzying array of operational +flexibility. In this guide, we'll outline the design considerations in the [`./network`](../network) +scripts, provide a supplement to the [Fabric CA Deployment Guide](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/ca-deploy.html), +and build up to a reference model for realistic production deployments on Kubernetes. + +_Ahoy!_ + + +## Network Topology + +The Kube test network establishes as consortium among a dedicated ordering organization and two peer organizations. +Participation in the network is managed over a channel, and transactions are committed to the blockchain ledgers by +invoking the [asset-transfer-basic](https://github.com/hyperledgendary/fabric-ccaas-asset-transfer-basic) +_Chaincode-as-a-Service_ running in a shared Kubernetes namespace. Each organization maintains indepedendent TLS +and ECert CAs for management of local, channel, and user MSP contexts. + +![Test Network](images/test-network.png) + + +## Detailed Guides + +- [`./network`](NETWORK.md) +- [Working with Kubernetes](KUBERNETES.md) +- [Certificate Authorities](CA.md) + - [Planning for a CA](CA.md#planning-for-a-ca) + - [Deploy the TLS CAs](CA.md#deploy-the-tls-cas) + - [Deploy the ECert CAs](CA.md#deploy-the-organization-ca) +- [Launching the Test Network](TEST_NETWORK.md) + - [Registering and Enrolling Identities](CA.md#registering-and-enrolling-identities) + - [Assembling Node MSPs](link) + - [Deploy Orderers and Peers](link) +- [Working with Channels](CHANNELS.md) +- [Working with Chaincode](CHAINCODE.md) +- [Working with Applications](APPLICATIONS.md) + diff --git a/test-network-k8s/docs/TEST_NETWORK.md b/test-network-k8s/docs/TEST_NETWORK.md new file mode 100644 index 00000000..2a97728e --- /dev/null +++ b/test-network-k8s/docs/TEST_NETWORK.md @@ -0,0 +1,221 @@ + +## Network Overview + +After we have set up a series of TLS and ECert CA services, we'll use the CAs to generate +[Local MSP](https://hyperledger-fabric.readthedocs.io/en/latest/membership/membership.html#local-msps) structures for +all of the nodes, using the local MSPs to launch our network peers and orderers. + + +### TL/DR : + +```shell +./network up +... +✅ - Creating local node MSP ... +✅ - Launching orderers ... +✅ - Launching peers ... +🏁 - Network is ready. +``` + +## Fabric MSP Context + +Before we launch the network peers and orderers, each node in the network needs to have available: + +- TLS Root Certificates for all organizations in the network +- TLS Certificates and Signing Keys for SSL server/hostname verification of the network node +- Enrollment Certificates validating the network node identity (local MSP) +- Enrollment Certificates for an `Admin` identity / role for the organization. + +In order to create the local node MSP, we must first register and enroll the node identities with the ECert CAs, and +then organize the TLS and MSP certificates into a location suitable for launching the network services. + +The key steps in this process are: + +- [Registering and enrolling identities with a CA](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/use_CA.html#registering-and-enrolling-identities-with-a-ca) +- [Create the local MSP of a node](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/use_CA.html#create-the-local-msp-of-a-node) + +In the test network, each organization includes a function that wraps the registration, enrollment, and MSP aggregation +into a series of fabric-ca-client calls. [The script](../scripts/test_network.sh) will be executed directly on the +org's ECert CA pod, with access to the persistent volume for storage of the MSP and TLS certificates. While this is +largely boilerplate scripting, the process is straightforward: For each node in the network, we'll use the CAs to +generate TLS+MSP certificates, bundling into an MSP with a `config.yaml` specifying the fabric roles associated with +the target usage in the network. + +For example, the ordering organization sets up the node local MSP with: +```shell +# Each identity in the network needs a registration and enrollment. +fabric-ca-client register --id.name org0-orderer1 --id.secret ordererpw --id.type orderer --url https://org0-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org0-ecert-ca/rcaadmin/msp +fabric-ca-client register --id.name org0-orderer2 --id.secret ordererpw --id.type orderer --url https://org0-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org0-ecert-ca/rcaadmin/msp +fabric-ca-client register --id.name org0-orderer3 --id.secret ordererpw --id.type orderer --url https://org0-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org0-ecert-ca/rcaadmin/msp +fabric-ca-client register --id.name org0-admin --id.secret org0adminpw --id.type admin --url https://org0-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org0-ecert-ca/rcaadmin/msp --id.attrs "hf.Registrar.Roles=client,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert,abac.init=true:ecert" + +fabric-ca-client enroll --url https://org0-orderer1:ordererpw@org0-ecert-ca --csr.hosts org0-orderer1 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp +fabric-ca-client enroll --url https://org0-orderer2:ordererpw@org0-ecert-ca --csr.hosts org0-orderer2 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/msp +fabric-ca-client enroll --url https://org0-orderer3:ordererpw@org0-ecert-ca --csr.hosts org0-orderer3 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/msp +fabric-ca-client enroll --url https://org0-admin:org0adminpw@org0-ecert-ca --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/users/Admin@org0.example.com/msp + +# Each node in the network needs a TLS registration and enrollment. +fabric-ca-client register --id.name org0-orderer1 --id.secret ordererpw --id.type orderer --url https://org0-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp +fabric-ca-client register --id.name org0-orderer2 --id.secret ordererpw --id.type orderer --url https://org0-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp +fabric-ca-client register --id.name org0-orderer3 --id.secret ordererpw --id.type orderer --url https://org0-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + +fabric-ca-client enroll --url https://org0-orderer1:ordererpw@org0-tls-ca --csr.hosts org0-orderer1 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls +fabric-ca-client enroll --url https://org0-orderer2:ordererpw@org0-tls-ca --csr.hosts org0-orderer2 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls +fabric-ca-client enroll --url https://org0-orderer3:ordererpw@org0-tls-ca --csr.hosts org0-orderer3 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls + +# Copy the TLS signing keys to a fixed path for convenience when starting the orderers. +cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/keystore/server.key +cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/keystore/server.key +cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/keystore/server.key + +# Create an MSP config.yaml (why is this not generated by the enrollment by fabric-ca-client?) +echo "NodeOUs: + Enable: true + ClientOUIdentifier: + Certificate: cacerts/org0-ecert-ca.pem + OrganizationalUnitIdentifier: client + PeerOUIdentifier: + Certificate: cacerts/org0-ecert-ca.pem + OrganizationalUnitIdentifier: peer + AdminOUIdentifier: + Certificate: cacerts/org0-ecert-ca.pem + OrganizationalUnitIdentifier: admin + OrdererOUIdentifier: + Certificate: cacerts/org0-ecert-ca.pem + OrganizationalUnitIdentifier: orderer" > /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp/config.yaml + +cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp/config.yaml /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/msp/config.yaml +cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp/config.yaml /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/msp/config.yaml +``` + + +## External Chaincode Builders + +Running Fabric in Kubernetes places some unique constraints on the Chaincode lifecycle: + +- Many cloud-native vendors rely on [containerd.io](https://containerd.io) to manage the lifecycle of containers + within a cluster. By contrast, Fabric assumes the presence of a Docker daemon to compile and launch chaincode + containers. Without a local Docker daemon, Fabric's default chaincode pipeline is doomed! + + +- For security and operational concerns, it is a "non-starter" to run a docker daemon on Kubernetes worker nodes. + + +- For cloud-ready development, test, validation, CI/CD, and production practices, the use of the + [Chaincode as a Service](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html) pattern provides a + _vastly superior user experience_. However, with the current (2.3) Fabric builds, the configuration of [External + Chaincode Builders](https://hyperledger-fabric.readthedocs.io/en/latest/cc_launcher.html) is non-trivial and + includes some real complexity for deployment to Kubernetes. + + +- Running Chaincode builds in Docker in Docker, running in Kubernetes in Docker is ... interesting. Let's + step back and _keep it simple_. + + + +For the Kube Test Network, we've configured the peer nodes to launch with the [fabric-ccs-builder](https://github.com/hyperledgendary/fabric-ccs-builder) +External Chaincode Builders pre-bundled into the network. When chaincode is installed on the peers, the external +builder binaries will be invoked, bypassing the reliance on a local Docker daemon running in Kubernetes. + +This configuration is accomplished by registering an external builder in the peer core.yaml: + +```yaml + externalBuilders: + - path: /var/hyperledger/fabric/chaincode/ccs-builder + name: ccs-builder + propagateEnvironment: + - HOME + - CORE_PEER_ID + - CORE_PEER_LOCALMSPID +``` + +At launch time, the Kubernetes deployment includes an init container that will load the fabric-ccs-builder binaries +from a public container registry, copying the external builders into the target volume in the peer: + +```yaml + initContainers: + - name: fabric-ccs-builder + image: ghcr.io/hyperledgendary/fabric-ccs-builder + command: [sh, -c] + args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] + volumeMounts: + - name: ccs-builder + mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin +``` + +With this configuration we eliminate the reliance on Docker daemon, fully supporting the _Chaincode-as-a-Service_ +pattern for building smart contracts in a cloud-native environment. + +- [x] Pro tip: Use the companion container registry at `localhost:5000` to deploy custom chaincode into the test network. +- [x] Pro tip: Deploy a chaincode with `address: host.docker.internal:9999` and run your chaincode in a debugger. +- [ ] Note: An external chaincode builder will be included in future releases of Fabric. + + +## Starting Peers and Orderers + +```shell +✅ - Launching orderers ... +✅ - Launching peers ... +``` + +Once the local MSP structures for the network nodes have been created, the orderers and peers may be launched in the +namespace. System nodes will read base configuration files (orderer.yaml and core.yaml) from the organization +config folder, made available in Kubernetes as the `fabric-config${org}` config map. + +Each orderer and peer creates one `Deployment`, `Pod`, and `Service` in the namespace. In addition, each org +defines an `orgN-peerM-config` `ConfigMap` with environment variable overrides replacing the default settings +in the core.yaml file. Note that each node's [environment](../kube/org1/org1-peer1.yaml) includes pointers to the +node local MSP folders, certificates, and TLS signing keys that we generated above. + +Note that the deployment yaml files include some basic template substitution and parameters. For simplicity and +clarity, we elected to use basic string substitution with sed/awk/bash/etc., rather than introduce a Kube template +binding system (e.g. Helm, Kustomize, Kapitan, Ansible, etc.) for manipulating yaml templates: + +```shell +cat kube/org0/org0-orderer1.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS -f - +cat kube/org0/org0-orderer2.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS -f - +cat kube/org0/org0-orderer3.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS -f - + +# Wait for the orderers to completely start before launching the network peer nodes. +kubectl -n $NS rollout status deploy/org0-orderer1 +kubectl -n $NS rollout status deploy/org0-orderer2 +kubectl -n $NS rollout status deploy/org0-orderer3 + +cat kube/org1/org1-peer1.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS -f - +cat kube/org1/org1-peer2.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS -f - +cat kube/org2/org2-peer1.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS -f - +cat kube/org2/org2-peer2.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS -f - +``` + +- [x] Pro tip: Run an early-release Fabric build by setting `TEST_NETWORK_FABRIC_VERSION=2.4.0-beta` + + +## Next Steps : + +After the peers and orderers have started, the Kube namespace includes pods, deployments, and service bindings for: + +- Org0 (org0.example.com): + - TLS Certificate Authority : https://org0-tls-ca + - ECert Certificate Authority : https://org0-ecert-ca + - Orderer1 : grpcs://org0-orderer1 + - Orderer2 : grpcs://org0-orderer2 + - Orderer3 : grpcs://org0-orderer3 + + +- Org1 (org1.example.com): + - TLS Certificate Authority : https://org1-tls-ca + - ECert Certificate Authority : https://org1-ecert-ca + - Peer Node 1 : grpcs://org1-peer1 + - Peer Node 2 : grpcs://org1-peer2 + + +- Org2 (org2.example.com): + - TLS Certificate Authority : https://org2-tls-ca + - ECert Certificate Authority : https://org2-ecert-ca + - Peer Node 1 : grpcs://org2-peer1 + - Peer Node 2 : grpcs://org2-peer2 + + + +### Next : [Working With Channels](CHANNELS.md) + diff --git a/test-network-k8s/docs/images/test-network.png b/test-network-k8s/docs/images/test-network.png new file mode 100644 index 0000000000000000000000000000000000000000..b993135c67b2cdcd5a99838b6e653114783796d7 GIT binary patch literal 225031 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
  • DzGDPR5p5 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

    k73?t$R6yV67 z7j{64?xu+_>Ky+Ez)f9zibzL#aM--j^~}p~`N^#+zfs>b%}mR+f%OJs`NSk;)6Sd_ z*5|TCC|2J-aXtmzSl!~a$>4CmOmj6`er&DMq?7#P>@PWv@_n1K<|^Y6W)8|WJ#M-x z-)0{3;M>f}YT0fH?Ml*p=7NC&W{q+;`l|9tw#ENP)>lAv(RE)7q5^_+Nw?A+(v6ZL zNViCLH%NC$cSv`4cZYO$clS3x;(4C;|E)D^DK6JAbMLu(@3YUjck(u|%PY+1e{COF zy!q#U+2u6u^?pHoV;sxe;B4~U>$)qxbY0m=CU#j_zE5M-R~D33rdcZ4t&Y zeiI(votmMO7@+UdsQ| zA{J~8I#_!X5R6U(YHo3V?GVwj(k;bar)}3!-6$7r9=Yz&mW+;j*#C?hpP{>Ld-mj z)m9BS>fSQAY#*igS!%!66wP)P(a}KdMAgTswG>r(wX^vTolCo>MhEq^d0gcVQa>>H z(^{5K0?xk8oGNAo4)5q&{b`j2$nxseKmRmvHX;RaAhKB-4Db?xp{ibW%k;isM~kAflJ4cWU16%bSdv+0%7+Or9v5tI9EivMUCb_*m4iZZ z_m8OHssuk#WbGXLGxxsm*cnfBFU@hpqh#vu5TFqNHA|Ad&+d6V2=T)Y*S#oE^xeP=G5;s}AWv!^Qd{<9a-c)tA%6n$ z+v%J+|8W)N5UaDJoPq#Xx7UBJBYSHo0LLz3kLzIjIt9osXZHhJBhH!26uxS%<GwMq0N6X3%!-NvV*qmny zo4zVZ|DK&!mBDV18@|L8IoY0OUQ1-A&&w$_PK@HR7p!*9Y#qR{r?T435%#-Tyzxs( zlSuq$ri;0)`#RQ^c%33P{%4D_oeIE_1DG}7Pf&`t|4NTumG0t{!}`xHI<47{-l`ue z)rmx3u1@{*^Hqb_b|>rDBG|7?s^_tN?Dwy<{*I4p=a7+;`^6enm9b^ZJnjtYd<%AL zssa=Cuyl3guGFH=c?UUHFOmsMHy4d^a((T93nxS1ghW^U9eluq~`TA1!HTN2wEZaZEU8Kq+OS-i|6J5owAPN=vq z?7JUb#!Sh_PoX+?tgR{`#VN1-ck&HiB{(e|PFyW|ZMtq7-Pi!qF8pv|H`lyBKuZKS zC?J~6o@9EM*l&5}nA$%iRS;XLwC5Vvz=>-tUp_uT_Ul&!>zTV23&5ls?vLfVj7Dd3 zau5<&LBbpC0|$)KX`8r#B=BbMW~whz65CbfqZ;R4cuW2WL^Y9Qc-6>NId%*Jo>$@E3+d{wfLg&y5~Wc96U#&C5QwU^V`(d0jnYvCGX_ppNLMgLvF?@(GsyMk&`)_2#tMS!Wtw0^oRi`e4%&IgH9!drwo0eeIudN^IwxKsFh z+~+;B!xGgy5}=JvP`7;*)G-T~%bCm;s<==mnE=EI*~%o4g0C%|z0n)rt2>PKiflJd zyuP1ggS*JguD#{jtUC`59%K`S60k#nmuoAYur$2RufDe&cU11#tIp5AO3AOzw^Zgv zKzS?hX*h%ckK^|sIDQ?EFn;_!EAvcPbeAaIXA*T1+x~U>nUMkD8%8HHGxiC`Y%cWc z!_vgs+S>d=p6WMI5WUs5&;n?_FoZcBP}l_mbTu|XDQ%xd z=@+@(yXbI21;2Q>xNArb#%1R^s*X3sejaqbtkCH7ZW1%v_l6yzH$S*@MoXzyz@gT_ zT3PgkAsU>6Dz!}(u)qJs>Wqj7_H^k`fo%$;)Yb~FEG#Yg#v0Yt%~1iyt0&mYH;W5* zjtX^YnjKqt`-_WN-LtbC(lZQ*2pF&KU0x`WWzHI?DRf9p_4G_jAsl~h)B}Hm7_{7Z z_ziVCBV8N+aN;wCVjafItFy+$`wQV3MD#cmxZJr*HL$=$(eM7CWS zu>=7HQD^D<5zs($gUdo;vBdjweAY$@QWS#Yb+O*1_rqwpQlFjE?5vT_9hEP1LPM@U+Y(vvfH<#=`4AyP8W?=ca)ySuDel<$>6dUrIO zgW4m{4NfWExbniwyHL$g_#;uJw48f(ww_jVQ!5es<&Ht^dHeCfVg7vs*k~sY;jrU| zte@=icALIGI?INI4inS_rE7#zP@b|MF;;$u)ishXuBRzw{xOI1)#|w*!CO^aYJPVQ zJhpRiXg@tB@E$=alf(U>hGvlgE|mr;C35M#~G zcDR1ozKvK?(({Z+3<>u$j>v6uJMWb~ol;og<-t#|U8GD))5^}eyu3m;+>w6e4=i4W zSZ54x#YclyJH$MtoPac z)55feQWa~nTOgs_U)i?^v7nxu!W$!C2q$49$yJdfVAz(Cp3JhDewa~G+JeUzDIot2 zeBLM8Un$REvY!v#S=pNZ^{c;G(-Z!`;~a?M2c-JGw7zy3ufO8?Ln$z$qK_n=pBTeEw&N8G7_AzTsEi_n{9Kym7i+ncrQ_NydJB-d%TYdu6})IGS5N*9+ zu$bIKyJcW}zkQ^kwy97dZ0U~{iscls_88=+E##;lX+PG#>8LlmceNvYsFZe(RJliI ztzsOYhf%Dlsllgd#EoBOQ@hzn-WZ*|amMvDoYGKAaHuxu`{__`!s;vXWf8y9;qEZ! z;JoCnFuJ_c!<+z25uwlvL=buPVrL`L;7UP#VKpD#IVjXyy|vo=Z< z5H!e1P!NGwTppo4f5dd;M~FBGGrA11%NB>jF~d6v8t2gl*e~&x*sQoiC;mo9s@gZl zrS=C|g*~uUDF-rJ*w)OaTAqg%t)oAnPk7r>_rvIc915FojbEgDI3wJNj%y%gchcvmS8M9BOw>FT1g{bSlAG468vfH~SP3^+TaDMP`mn1@+&%DF6)hM}YsA3^_)wORV^@qiLBk0^n8 zYgyRDNYHp%Np%sRXuUWa)PTHC)xC}U1tG0g=+a>k+F+{sO~LK%XTN=oEry@3pY(wo zPtwPMqny@ctc?CNJXT^@DT)u{IVOj_8RkmKIR z%FKmq>}?fxgit$8SCd7ubmc#w+M~F=ylty@>G$>vklJ0rY0uqZr=+~EALY}tBVp&z zOQ5&)&Ov63c{_eo=gn##B?M0S*@f3HBCV(XGf2F+a4Q*<$_JqyCA-vS4ZBsv;%_>B z0wB6z*eJj2HL27LyCe8(*p0kCNB(9@KzopWd6={X8;DOGmNazL-0Yn+C<<}noI$`b zmojsBFqoCz0UXw|oUqpOR;eT!G!!GteY*FF5@_njXB-N$`~6O+HD@^OX!E&$YsT{L zj~A#-{p9R1p>MA(I)-2E%Mk;Iwoyks#$~We9%N~|0)?UBmYqRQStb5Y&N&r98TLAM z|6$SK#sM#S6bNWaWN5)D3|DmyHuZkoeLfjWlv)mU_k+wuS#60~CWKeafqxUWnTX7U zHxRrA?oM8Gw|W{h*r~YN+gC0w&(DwaZNtFM_6gV-FG&rz1 znw+%R4_H^XD@Y#KB_D^Ty)Qs5Xdm|*N2k>xKVD`RZcKnIT>)WkLcQ*k6g60Whvk98 zBPnmnvk_20Oje;u%1P&Li8Qq}aNR*ubKF;UYd$NQ7?C8}fg@@Z)a6)W{X(ndcSVBH zT>O0Xiq1ESY_0e$LzbfS*gf(Fs1Cb%tinAEoGX%h#5PMqY_x{M8=oA1zin!b^!u(p zRD2rjJP`BxW4Xzl&btRZiAS`#9?j_Mcj!4wJe-;~FD-6- z!9@{wTs>*GOG_^s_afhGFJANXL%|bJsf|M@DJ%Q$93RtL6;$z7R^I8%Rb=Mo(q(6m zuB^S$gJe0Q%v|Ak8a~yBFz@R{%C$F>0hgD5)D%$G^nL(s?5xf1`HpYF zDeF*0Fk?$_rtK*6gX9I%i>yU$%}`!K1#=%mU7T$Bk!$^_l$x{HFYBxL#W4};0_?LP z1&hHXPeL%PZG&<-YT*VC!a?{AK3SU$4L|3!O;&FY%b zHXm(1Zx7{EKPM;y+c9;sjFWqzPM&7c%+Of}vF}7w%Ml*2JcfZ3;L8EkqIQ$NGvl z%WQb~MYckr0cD}~c!krKUO}3to`#jWTP$@|2Z5utXW6Ma2+BVecXs>_QxO-a#3eaQ zHdt=NTJh6&qe!088GDk!Q2nB~3d-^22o=AI+tT@socDtjUSDIN5b<2o5lpPCJ5UyH zld7xtx=h5jL-If|*ysdRSy`!e5q!5XM*L2KUwsV+|Z-C#I`(>)!kYHIqorNT%cTTM8Sn(x1 zp3^>o_pN{%!sB2lBI<0&I|+X8OBRw!;xgTlgxQ%#N^atbiR?U8v{HAw=)~io`)rID z#Ay;MaEw|okre)U9|h{=wMJ(Wr?ALC`*{x2$Hf-r=Hn&*F3lud-zW#FKH(px1G$?~ z3|5s^nVLsc(!f41>}hLUmstJ2$(t}z6}b5vji7-x{9xJqzdNc?1V^X0uy=R$-C=(S z>(GiIBVG{=@`D@BrMBIU)Fh?d_@3z!5HdZyUJXI8bMlLiOMgFDAM#eno{O6xl8Prj zvM+Q+G>Z2l{f-9wHma2_O+f6PT=~tQgiK2NxlOmy=EIP@!OjjAZmKMObquD+cj3Oy zcKk)0TIovLt*I=+YG1LGxzozJaklW~ZZAv_)6^?L+lHoFh@hfj{*mSJ=^W_p9~stq z-97X7MASxwP<-izT8eR#nvTB&l}{1H=?ijptz;0rb?;*auzboK(~ z-OM7#i6h&FNC3c^ki$s*8{Mo2koU11%B%^~nf}!;pOfnHI=;2m2|23obT%z&0Q@7?;KGa4jCM9h($&{#-v%`oeGCLsR`;ub5! zzxN!kQ|agsjW%Fjwoq@-(OlFFd5IM${+6SXcy`4t2-R_eId-bTW?Zbir7RdtrhWTYxX#Q zZ_0c2F4>oo7C`i?^Uc5x-1?V?yua1ZMLWz;Qv%25V%$o54O;Yqp{Gc3>X1fA0+_nT zk%q%3pI9n0Gt+)J5m~YJAmg4V7+ytqbdOoYc`!D6n`=I{V5z@fT#n)1&{EUx(`9XC zNL-G1q!fw(|CH7E?uf~`A+sK}08G!18H+&JLk7bEh9@c2If7kmeq3a4Ou%_-mZh-0 z(sLoS-yj1Piplk7TMr{m@~Ft`=SMJ)Y$Ae^pW?3UC{jjp!75Z~FC>lp4UFttXknI} zZEiSyDPUY_#2>|t350?^WrUi728U5rnN9yM;tyo?x%C4zMh#!vFaSi=!Er6_wMfcF z1U8ORRU|d8S+1BKenqoPCrxcS-(B1>jKnGl%rMZbQk&4 zlPkRi-__+X@-7Ifi2RBoLA@N1C+H#iY#`A?{XM6+m$jZ(GTskshm+;?%iWo=+rEO5 zK$7}_568&_vn)uW*3=xXH?LwP-pA8k9LP=~57$Oqw*Tsc-Inq8dbTjPz7oKZEMpuB zLf3Reonv0V^k3?1AiOJ-1s|2o4%eNB=J~Z3BdX==jm*EXI6&Rt7uFmm;J7##f@E{$ zQ9*NF7l~&)cA~~IwuXDI)&{4DFMyQJW7lJIo=OdrIsz57MHwjDz04bEfs{{yCtDBh zk(PM0w8C{w<1H*tQC6W1+omWl05O0%{dpP{5>4AjNJ2Nmv!)7z+R@Xz)KeQ3apccreVNoeb7eD-t1Ae{CFQQh3s*FRUZt3ayHma-F3anKIOD6*%a99MIIm0PQ z!#5Q3VNrg?WTevG0p)cyo}U(Abm&0wBS(_tN3r5Fx!gwb*&2=+i^T%#?lm_V>nOY@0rf<`H@-QbOp!9}FLgy=X@4u=aOe$m~RkB5g62(?yQwV3k#4 z6rcZLFb{6t1W~dU(AcChF1&$I>y5cOIw#m%4>iP#~Y{z{I+R-1!#!>TFAIYz3ed-UNTj0+odJ ze7ZMh`>!AanmzLvHT(ctq5j-!xki2!lHXNr>GQ2^w#KS;$9hdyH>+~Cjte2Rb#uZl z`2XXS(vUD~u&YhP!=j;JT#Wi_C+sg&<1@(OXv~hYHSPMBS6q)weU#kQGr*P1k8||8 zNMe8r68fNHTx3j7tp3V~Fj}jR5 z4gsCR0iK||4d(g&00-3_)0z27K}`A6?7x7T00aBDrc`W}TAZf8K6MU3H-b8_Z8+pb zC&_ZRz!F>m;J3KHi!UM04{gMyG!C{x9v&`dc8K0NE$dd)WTjjS^J2m&XBg;os zlVCE_fxSh|mp1AuE=Z`(vzAu)o-Q;h2p4Y3sIh_5SK2G3z{x*Vw_o_3LOGS=Y>=V^ z+*h7HLv3=auTn`NJsFrNj>EGYXI@bY{xG4kigN<71W3$K zZbC>&ogqlM+y@uqOprTUtRvuyPK3NC!JEyHW~oZ8_SR1XZ{=luv8pWsWqAE=ZopHi zK3VQ04GRS(Hoq}%Xm_)og`qBLDrLnNfFwDACpUVr>~T$R&SQ7%y$kPylrf;&CZ$C# zQ9^@e&@`gd@K5l5#-n4GcJ)TvUOskq;Qy27!%$Jjs9E^#2}4S?z{}-C42Oh7Xs8M@ z8|Ss1A@~YHgSgB{J>fRz5nGA|nD~>d$JHvUSXx?EzhK6oWIVW?M1xr1Xm6oS#|Z~? zl!d9~S65Lit828!7*fw)J>nP)?CP---}@(AWO)yG6sOLbK)IuB3YJa!4=v$qP5$N= z|CU)4!WxT^x&#UQLih?=ZmnnCDysHTW`1ENkg(nmtK47XzGtkht4GuQOC%Q!5yJx*PCpwpzkv{-atxx{%BO4! zB1@dZbPKCLL!02fnYgcp&(@Z8MeH|Y)8{yM-H#A&E^|_rLZwh5LjZA~90t#`kv*f8 z!=wq6m!du$+RfOs=m14MjL{0F5E2L^J5c&UPhFo%x~()2Cn94TO@hM=3^s#jhC16n zy!;;gYe*Td-$}25w2VxPfPr2K6EFv5%Y``4b0G6L2VQxX-(_SLN1gkJRAM$9=dIUa zdZX9{C62y;qe7kRy@$qyYaDMmGRO4`017)Gu`&1)N~zMOYiH(Py6V+IH#n@FLv=)- zYF)qeWI%sd`-so+KKyo!{QjnZ4CdgxO*3dFc^Kp>f-Y`-Bo>QO!A`u6aQl@NS3fE$ zsysu_A)BLx6(C*EO}y_{_1}-k8|e-ri5Jw;LQzuAs~EtU_d^$pfT|%_K!t}SWyTjX z(PcYwFQ-SUxyl+u2aS6nHMq!kqgD;mmfvC4MFKF#Ce{@b1+j80_eUr93%JG(xvi*x zIJh{wwp=1H;#kR&dIGZ239l;f&1hb@(b3W7I{DCq-1Duq?mq=8+!REQX*Ml5?bk9Y zmQ`Kp*oyt8R@#1==MC|saOXH!|T2yjAR(u;=b@MylL1T2pqkCjy{02u-2=l35WVfH+u zy1Sjdn@GP0d3`B>^LIT4n|t)=cXsQ%M?FiH81WZSks(1gyRE`KW(|oalZNCTlOY7f zcVf_63lY)WZ?6jOb**6C+&aJ`BIBue+jz%j&=I@nWLz`V>#KMNdwdHL+%&cc;&MaT6Kby*>^iT0iS>(*HuV`>(TCsJMuDg6N zSXYtBKu9zQ?;6^J!X1v3Fa4=$z^mZx`=vHBP;ltLL4dajwgt`GCU<=+Ydf}6JQ-Sn zD#U+!5`anpU$eoz=a1IKv_5Wj-D@CIv)RiM8Z1%F`0oe{;}NjS1(csJARwcLHx7&| z0((7ekne4dk;099I;fYn1JvdR zzd&59rG;~wKg4Y%DnwwsFcYG@Kb9T#Uc)v?Yui|yAhBV0cUQ~HpxZxfedhndkshW{ zgF@+RufV^R;$h5D&tQ~WP6%M{Xu$pik9kcx9mo?iu>qIzmN7Xb_(C1oINgDE2L|?z zi&WeNg2+{s%LLQuI%6EqdD-^z)y1;vy$^tqsoxw*5B89WaH^4)dnXxoW}P8y(V!U+ zmb~4;pjFJLa{>*Js~oD3jh!oBprC|jccd)Egr%MMGvD7v54FT$eCtpDvmty5qbi#9}iQ zw7kC{wAKKuG_pR(r-@Y}2j{5i$VpzcKL$#2FEs^W$68T4!umC~`|E<=P?rC=FzrwQ z3M1-=#i!_8KR;BrcIYJ}2Kttn_g(GkZERniN*%WI@2u7dYa0BV)#qFIqD7n?Prk6S z1Fn5ut@5=XK&B5foY!ydP*eW_g!I9^0>>aR(n8`t3F>P=prJ+T>y?CsA-z7^|KoVa z=3HbZX2r0{kY-OOE4#hp=bMY7kf!}JH9K3OQpLPJ-F$h0XfOg&iRxq14eLFRib?_# zr9`p~E}a2HyMN-uhHe6j6HHE|bI{U~MqXY}5Zs>q1_FfF-#crHw=16gEpOn|dOUH1 zqeJkSjQql63SQ%?s-A3(pb>WX^La(daVXZHqM_)Pt5iykkEX=NlHc6iAYjabxp@*L zX|hX{(f;b-&p`^#;J7&(Vms{8_LC%2GV6Xr2EZNy?s2+}9s2#^P zv*Yqa^ug|l1<1=JIcad?1z#$3pD4tuD}CO#wiAcNGO>MUs2DiEI&iC64CMKu&yG~m z@Y&>@cA=ES#bg98VA0c-06yh2;({2Vg%zJ=7RT%{$D|#@ zw&6B!#9tmp9Ciw`w(`0k>n|+cQK{y0EZ!}7IK+v53RE8tlDd_K7C4Rr>{R-66&|Cx z8{2V-i5hz};5dqpt(IH4Xp4Wlh=>wd^M=zy;&u$;SRJ9+oMwLI&sHxdyun4yhj$dq zp%nv%MLamlwk+D*U7b{O6hTS%^SXC)7xIEzcX+v(UcztVK?9rIEg|WykhvNaFQ~TNm`kl(^sXS>C=I-Q4(WnzyLQf zAJbIKYx^3q7@Q*dan3*#@*RwhsO1QtKlpi2uzfh-E=bjlW(~m|8fVgYd(}gl& zd^#n_>SY|#1N#7LiT)8e;ONsCSw(QZpFWc+?*B)sjqkxd_tA14h32BPF9+@x@g3@H zU?Xy8ypN8iTI5&if2lXOoM^($y8;EgwmCPUvh}NUCPlUguO^;=goH9Lrn|c$`@_p- zl!>Bsm!S(YEL-l)lde=+{Wau^>&vKjuw8ufB@0G_4Y~sMHq;t=NFzjp?;)mY2Q`)k zKm3+a;?dR8Us#dU0M~pz3jiGy#cHY$1kG;YJoa!nuF`o|mv%X|j!SF1xW-O^#zeR@ zSTw7wsnJ*~g_;V8UPL!D&%yz}b!=Me1(8D5J@^M6pWyED!EY&0j(`HeCS zE%F5ym%Hx>1+TkHa{XZ3S;KuFhs{Akw27$|BAiqV>8DUq<6OB5702{qe?SKLKw#-o zMtobbn`xzv>3c8Gm@uZHYx8X!6g${#{2H5R_j<^D-=C{1KnW!RPwgSYN+n)v=X~~} zzCuoDP?ibcmam)+)fyLVcFbn?#HI(d@SV@4{3AJC${Djrjn3*p5KlE)eA`mYzXkbO8jq)Zk^8(qW3 zuj;(Bc16Ru_2EJGWWwRy2eO)9OT}Z2U9=BwT0P{+4o(3~D6_2p;CSns0im0;|aKO zX5JbqOy}3zCF8ql%ogu8d^EphD6ew}M&d6(T$7{=g24LaQU~PZ1ml`s7av)3L(VEu zMWO=agQ`&3b_Rkx!(0d?Wt6?j_M4WNS~O=#4V7_EQ9Kvo+Q9INEz8`gpWnnRE& z`r8GWB?^f(YHVag%r;`5>a4Y`Lr@>L4)>OfLj*#R#iWQ<^VQgKzG@)8N0`fv9NNt6 z48@d;Dx3qg6fSl|88Nt_iq23(Jw?9<=!Wk_)PR13VBeY9>v#HMtGbh_4kg2xn6`+g z9=~`~BVP%k#6&|vpNzYs4#&3t9|CiXK59Rx2%7Ve;8b)UE;bWmD7L-EF~}b^MrSnp`Zl1 zt4b`h(-S1V+8zaU$e+&`6BP%0413C3&wBxF+1PtHIN45o2xw?%!i$2U212#>{jrt7 zi3N-y39LYii#JZs<7x$ZqzDVzLh;8n?JtRkfK92OL_-nb1FOvTpHW2{%^xNd-~xZN zY?fm!JFDa}G4?hWJr7@2FQc_wGusio5zkoa39y$WV*1guKrViJy-ZC?z{`%r2y4c- zp1-VJWYNJBH_$I+s}-KTw7=}bqs+F{p6octN+-SABh2$T>!uto z$RK89bPqdX_9Zyl9)tCg_{^As5=b+3A|YyP^_XEq(3D_bNw|F)`x|N0v{$JGou)BH zBOIxorj$M-s6(-U z9TqT?QmyFJS-7m-Xkp036WL$m)}P9XNfNC8pmKlxMx*^VZL`2si=}T~yk@*-FP^Iv ze`8x422_h@4#xgmRSTIhi&SrtS8_`M8ufjjz5_kI9&ZKE_l`a^E>$0ArwW{m z5p#gsiu?a8Nf~h3fDbqoLwsJ>f0s8nO+u34Q!C2oX;e}Ba|LBV?hDD-oddFSLWL;i zawz;ynqY2CDD?V_!jrh!7|z)1T9v?|I8KAhS}x%@Ixes9dv}aWLJzOCe}cuXb*#^t_ZdQFFNjUkiOSG@fh?B*>`w-7)vT zowBZBvGs7>3W>Z);oOI03=fPA5068fBIX{oyN7&1+r#f-{(cQd*gBG`Uz|5?VR`{( zMFc_qK0#Gn$nN{Q;*w){phXw3rOMXpU=G@9)glU2Y5(}haZ1hP{4iZ&pPgS zbyr^vpi}!l_;M21*Cye#dkuJLtajCEH2N4 zx@$Qi0s$ByB>mb=7N7eyFJ&&o_0WN+ynS5w%p+>mdVhw+#T2&#ZuM<=l-Z`to|I-@ z2#D7htF+Hn>)97jG=x$DYyZ|`i0U~SxFE7Uw4uy-d{JIo1k%d>U^4DWMgmUUD){zY zSy`EMf253!(bP+2f&AV4<{Um2&XP%-{|$ItU+;)-nwBoXEa6zOwr?RfSDul87BRF( zW=eLo6{k>t`toJf{PL-gv1^5go4y664KWxW_>{fxK&w6Uq0(&3IkKmr*m9q(O2PT) zUr-#V+PzdQI^dWk0tqSuQJ`HaPOqFR z>;zFqu#q6xWf4_nO;vPRPW>1_iov-0e41-IhKT?-8-{QT>!4R#?0Sx5i0h3^muV{2 z@%kl}8-G)wu0G%JSO}K%llx>rGuKMvyhnNg=(v}^ez{SW>waqrmd)sswX?gWTZ=`E}E*0TFvxtDn#HvA2*!3I0vjP2qV| z_NO#^p_{X{!vop_m^i9;LGs17c;z^spyur$5W(sbE*9=*v#zocQvz=@`j`Cz?1N*z zEmzTRHxpA#TD>?I#me5I7q-||Xgzzho zRb~!*hGb`x?MziEYr*2mEFTJLMe#Qi5+b0@e_mDT9OzKIKZi3=X%IgaPlb-b_{{0} zPM`Z-w}8qk{STYPkgxL3YiJ`>W1)pYdFMW&56MT@IEoX z^Efd!INKJVdA|Idom=0zxWbUOI>wH6cz(#wycpjs#S#{h;~VEOKG0$OUK>Q2LrV)$ zq(<-ks_yN%JWss8onrb{dh^+OS_HMcJ)g@IAB!-|MR8^L%k@N??HQ^rb9M@2j?8l`wOgph4sG z&t($cIJijYZjvl`@E@rEz=@%&E6i!GAR@xkQiw2~Q|w8ApRCSna7babKNEPWKb~|T z<*FworR2ZgaQ!+XG;lfp8rL1@9w(#s7nXQWeY?s^nUi}$2UN#k{K_uUJ~F4g%fl% zXfLZ<@dySRRDK_Zw1ayyH%z-U%yVI@gOziP_O-R*I5+>KizD{2h_ftSB5H* zpcJ&bDJ!7(KjQ-oQPL&Edrpu(o;1W9^MvbnA86`^22lezOXn^Da&6~rq{V?h?P3;6GpiVDWe0v?gAuLndd`B7bY znkvtmyl8c|O6{gg{&}!y7eassaRDB@Lm6TM{pw8OgV`9Qi=AsEoBPZyl*ru&SIv1h1A1^Dy?CuTG=a z>0}0iD-%`klf8GEr(0kbnNZCbS{Rs~Q8Wj#^zTE|#1V~a=G5zb|0gUTuoQR}FMRGG z)OW`+Lz4fFNg*6KRErS7=?!mRl%^1(Y1TptN#=(-2aIdyxm15FPP0;9W~QaBEl%ODhL#Wp}Sxw3J)%tH~AET;!Sp-_xsF z%hPCaCAu*?N&19(XF-ASO5l%zQ(+?9Ys(xC{}l1n9E^T(ahs)|rkSnI4MLygt0L^H zYQa?vCIVKuu$xPh9ZfZPRmHH>vw}R2zL`_2jqVXwa_;1N#zKTpMGlXAGU`QHrYWFzMl~w2QVBuIW|v#g8BtEFmPSEv&l0v%Re$(J$DfT z;Itdzk`ak^1&8HcS7WUU17MCT6tifP#B>E2NlQL16lqu=WOgA`$hJ^WTMSCiSIg7V z!JC;Gl9OhVCukdFf;6Et!kj16ewLpgH;&}pPO>{H>ni~klPmVumb;n$?6KiqX~)qD z3ceU5um&?=NFh96QMU(_6NUFIsD{%)Z#{^!_nSlMdgV)AdWDW0)F_ewo6K&u**3+N zhbqu?cE7lv11Ar>H}%*O<~PD+gN)xCYKDh;>b!Wz587C$2#f>p$D1pjA?g1+4mu=Y z+ksQMYk1?um#xVm=&T7EZ{$OCmK7%6AuZ8RiBw@10RW|sl$4nt%@p-FNm6ZhQ z6Ob}Se%`UMnC$MdZ#gQfYPP?E#49Kcl9Uk_6lSOzti)p;er^%^O{FfquViLA1kMYB72&gQ(47AoDgM&0MaqeogIdD!5x~TS`wb?za#DITz}LYC{4iR=Z#xL&2vR(0zX8#v=29+`bD$YA)rNia50KK`}0!&Dt zjuCG3!R%@U%3X-Rae%8)WAu2vKRGQ;F1*9a{~NH8>*>uoKyQxIVA&u2_~t5*$hacX z={6l5IV^;M5^5<2Ql=!Du}mS4(3%TH=Ie3pZRnHn7lIUS>(7#yPi0m0f+r6LZN4)z z#iZ$rd85gUYWeHqulVg79utLX;o9gvP;ZArji{)+A&>Z^3%OGG+-Oo{Np0i~+|?%% z9@~I`dbBloUJ(wnHf6+3CC>D9f%n<}{~+7zp9O8lj}KnK^Dnt57Mlls47 zAq=lV38EFR)`O7Ltrhw1O0!jH&dY^)6NK28f&th;z!Ko$R_pTws}r+RAgjMH2uyI# z$syPHP%6p()ETeS0GL`8^ZN<(&+8LW2Lqh&+M?+O*D58q7Z%yHfW@YbI?l0o2Ff14I>)*Q79v zc`3u5j@6haw)1>JOM`cg6J?s1p#yPDN5S}*BD8`PdmOZu?bL(#<*8c|LFi|SiFtO8 z&luW>04Y~fKiQ%{VXL5DKv#SKbQ&pCkfya8PW%NBODb`tdpTv>^NJ4xp2h)X)a6ZLuA3L z<>|c}XBRH=s0xku~YTuZr|guHa8EyP^7U~E?pnWCIN!X^#ErNEpu+uqfaGBpSDD| zPYc2l*L@e(%*L|`gjK6}K{jAMlo%NI!5$TP(td@l@O8u6S7#`U=z@KQVY{T-ffRSB zGB$S(^7CnO;};`_oK_-ec6YZufIjdaAxBlxsV6{apkwb7-PtiG)=%=9gl^hj@q2@3 zpPY5<2Zf49_*#P?S$-tS$CR!ZlQKUC>@I9oAKI*;1o;s21DQb*vf3M>o%-0edtHHp z4V~Eoy%{njXg@_m5RhU6q}o`J8)FRhkHU%&f#?Sx*V0`Nw?`FTxNQr}o@`VB6!!qA z0TgP@&&v~;DUds~TY9)UtT`K7{ONn)3ti+;toWn59WfHZ0tx&&NuSs1?~e#Tu~SSD z5FuZdA(h7Rs)gHMjNlV-gA1=frQ!k=_f;#c;3VTD>oZvvLc-qVlaD?c!@f&6gx57X0A+wfBZM`*Fikbibidz z9%UHa?Sv-BqL90>Z%)SQ$GQF7I*iZ0iiS}17M28uYi|edIx#(U=+*im<8I!&VOjvN z?>vL=f2=h8XaNNUjCs044T;aAt!SORdyMyB_Z1wONs-UrPtbffJjpu)T37ab0*%K& zI3fh40-wc)CejrLF&87%0fAP09|+^9yrn+@)R7SuG}3Jgl%fkZWLZ;f`V@UVLAUVS zkpRtS1pdv0QK{o&k=f34+Z}OIiVbOo-!pzyll~M?za*7ebY1v(rll3ETFk4+S-cJP zk7m8ot0UAmrR+J_*cd!NwN&9oGN)j26<6{hqk-M`nrhz&%TaV$@dsFCSMF1 z^d13pW4;b_w=$Q0SSeUK`0}%(1)$$zbdbVIDG42ms_n(sv$6qH<&4kSp`i`1kKJ7^krTC98$*?ClhMq`%EE+WN(VO+0|lWZ)yA*AVUn%Y5Fa)-E16QS zq@@_tJ;iS$Y2Mn-*)xiAPZXfB#_Du)vfW7O4<$(TBxhHvry>Pk0TUcIY-58BsZYhzBjk?^oEf6vt9E+%$dRGpw6JCnyit~WuvtA;R3$yE!W+EEazo+D3}b?i;L66`%AIzT=bV;Tnm zMS5N2ciJwTxPZ#>63YvE&9Z(kunamnBxd2p!Uzk?(mINw!{*fqNsCj69OUe&6ve_v z=gPtO*vYQywD9M2zO74Sg)1ti^`n%wPAYqG**;3;VaDQ1oKRgJXj!P>9*I7&?h zi*3n{b!P9sDP1~+vk9s<>^y}}oe{3gcc@>VpV3hfPK__OhKKiKXlU<;sextqrVr!z zc0Z#=y|{C38(wc7Ybq&&Mo=$=|MRW0*F>#SM%%(xv!cz1)f!&Ie(gsidEJ|6m0C zR{|z^&F#P#56Qe{q|M|c-~W)}+d2;Mfec3&xMSU(Pt(-nF<&E#G9C7EFW{LThs$ut z-roF@Y_Btt(k*htYz0Wwp12Y``-G2QPpuV}WM;R#Hw3CsZbf(n&%61zj~*BeBTsOn z*|)_cWt}ec3TLg34|l%ke5c`T5)}GX=y_fzUv-hXGxBsSaxJ5?Q8BtWkIf_@)x9=i-k&_zpess$znku(lr3#RB^h$m$EmXBC2nSK1P+~K0vJsmUO3x1cEAN=~i=%#P3_1F#-@yoQn%aU@2XW-kx`x@PR z!-@qL4Z~b2tsC=)bpIuUem#8ThT^L}o)KHpm;W$4Xw6r7OTQU5(vO5TlA2cm+bR2_ zyp;JA;`Uyte9pGMW-O_o!pMlvZpQSjxHvO9hJmZ*14~4(?P|WPLhJjI*DhcZBloKK z75It~H?&{lBMh$3$sj`WIHr2?I7D{yiClslHF~5kjCXrf8!L%ieS3Odjy=>(lG%#a zbi<-}L*ak?IgyNFa~Huvd)=Ag4#T~sPQR?XNM@nV@OM46hkrC%bt|3dxf8XYz=|uH zGp~+N#)Z8@rkc8qK0yMzyO!88U~zP3!?jSlt@7Diq{z!1hMA)e7lEU0On1Ods>TI& z(tEXh=TIgC7Ws1IEGeSF3owESZu!_W1LmkZhowQ%f*bN~q6jq_pfAbko7+25b?t$p zQ?~5;mbuh)C2%aJF9f46-W)ksCaRoz8#|3uNl+EC0IJ7MRG?xos%*-c&0>jpwLG0L zZ#Jq;nQ|vZR>7@wV9+Y9?EQtIzdRVFL-#Nj z1sY5gnN-PCWcuzbv1!~(F?{`J&r$*cagA~nEDL!ssFIUa5E)0AOQo-K5Du*wsj=>y z7Zn%(K94%O_F1_45HTM!IwpqhbW*=T<875Uu;lw~^rMI(WSS$=%b>^rDIBg$tY2 zx(h5{#7;?Js_H_}r=8NwMRcrW$Hfr4(~nl^&rg8jdZlV@JoBiB9cqd|BSADOIFEK> zU?UPZ-w=pBdu*&6+0Wi$C!6w?+FbHoXDTTTg;a*UYjJcU zq53SY&BB9fPz>(}uihjxWo53J*G8$jrmQKdEXMAFiB(BZ-wb;#Pvr~k$cEAlvCK>z zbw`FmXwZ9smSIcDF;m#vVHQ~RoRXhht?jd`>&;E$bEJN{T>sMFzoh5CAJ$?8R7Ap2 zJvKk0B->cutKrjdSbIa!ohu%*oK}f~+2&>#7hdC#dAss}Lg#(GM(t%|Zt*+C-ZR^% zMS(>)cGFx`)%%3psmEqwDFyrATs?>o7*L!-PKGp&RyI(ur_v3zf#Ni!B5m$@*8+Jo z%|)0UOj?D{UMM7f4o97}Y$GO|cHdD*XmMbdx&>c`YIiJ%Z*B}ajQSldppU!$^+gOttcBIYp zmz~qRzTL#(_a7}{TTv^oglOD363G3Uv@}Jsye))~jnMrN=?enME8|0>^|GNV*WmE8 zscIIh<~Ax3h4Y;yQiXG%J$RZH`fksgh|CwC`0)0S?ALf-+w+}1mWx<+JXY{~Kv=PX z8Bp!!6PKDN+qX4e3EV~dlq7@^?Xl;rtv<8^?XFi724W_KnE6V<_8@{*nIrje7QliRqG?JYN^L0E01l1U=|H;`7VM3q#=U;dxn+p?%bv7Av8k zSH&kb#dfnjX!rW|aO-D_mU-+;6P75Q_+5D`l~wLO&#_xZl!aY8>5}+&j=DX^vOfXM z)4aYX8x`N4=p|y=ETQ|KY}DM@aNA7{w-sBB=LULSoNW9DdwS3sLuX57-U6*r627#% zd@0z%ew-Q(d#+X=t;^$b^IkGcth=(6e!ca92ykwdZ#L2vlv(}g?OJ>Eo{*~o@3w)w zcR7=4ZFW51;QBWxOJ|2Mk%8<$V-258Q<2 zYN|a?$3p&DUXSD?Ec&Dp=G(9QVEZlarHiZA2kLSU zqYzYr#dtpSGhVLURa^@+^o9Hh%P0A_|C}yy=YtZPj*kUqemyW?BA_n{N12TS0kFE{Fs4_fR)>nj661==WLrOs%!TCad0XPN2XOW>0_onFPSL3 z!qqVs)3HK4S!J3A$LV&#iu1RRs3j+z+-qLmnWr-U^8K{(j-nY#IxKlC4-Jo_si@V{ z%;)ai+k4o|AIr45#Kl|P0TuTJsIyd1$%=0FkN&JRy==M=C;0gFTbmMhN5sTA;;=HJ zwj-6{9*K;ojVd$hhmDO!GpNSR$awZI2=F;w@UuBg!QEua>md&yVg2uaw*~6-V6%A~ zr_Ab8NrAXvR#lov%xil@aT3n2nixwb-SSQSK4bp0)m&ez-Hx#6jZd0d8tZA_2tP;z zx}DAaT$f;VJR^`~qKv*o)%V`5^7>-GdV_vC=R(?!+z%^)kUl1iL zr;$q9$7tknE0JjEV~L1qs6)_c=JR7QPLLUyXtF{Lxamp#8xy+!z z&5(|owEbVOoaTV>chuT~J}4qj4zy#1op}Q=;0Jwmy^S?^Z60jKbbgqc%s-Il2+(9W zdXyg&GIgWsX#0YCP>(|jFZj$mXu9#@1Vw*tFCVLLa(Nk-$qU^BJite6^Bw_?7awmW zF=ZW*CWCTz;6cBAHk0k=CkmoC^*`$%{>hTRc=OtaSHe&PU)*RLLg?80Mjsn#52YKA zHB`HS>fVOo6*vq({Qg~?)og^?SbRU#zaeH1<(?W1X7>)QIt#P4LTI8WQke0*t^NJy zT(XBr-m5V#ynYD+E6s|5LSMRA-i%o|Ffx7nIHWVyUea#iS;lFPS&Ve^{IiNTizr~1 z8VN%8Aij_3csxzbdw+=Z@W{!86hUrKuV-z*;|)!sb596Ipw~1oiNQ1?2Q8k}?bAIK zJ^jH6{QgWMVG%jg_i@xV53=!R>YWX70a31fr3)GW_id=;;A7kupodcLeqk3vg^ge1 znf>Hzd;VkD)`wv(8gh3J7BP{R-pqX6QnC7$d@z{?RHi#qiG)H0VQIJ$0dX^@(r&f~ zbZC_a{X?YVU#{u$4NDabT8B--NtTTKixvHsf65Rfrv9vC6dDz$Z{uJU3riQn1T?mR z<5nWcKzY9aA>r!uGzgf&e?L71FRbi&Qc|JVU0{q-?#x}`tSpmJ1q3OAyD$Z2k}!&f zSQzS2_l424gyF9_n5xrM(=Lzede^1X1Voe9OoT0J;p#5le(H3F@Ndp zvbKoZa-nZl70p*Sdbpn7p#w%x;sPzcV!?UQgbvmu}-&$Bcp29WAh}G0gZ@G z$E%JC^cG?iKZLW$5pdOB3yrXo0eeapslq3tUeDcq@T7-0){6a&UIN`O5`%!?!Jb?3 zMJI{q63np#VNNosNa3oxz7~BugcKSwa}Ot_C;Tx2nb6O8&7Z_NgbFGU)SX(Ihi0(n zX7)?_3yl{$L&=a6(g7`99$R~>L?%zQnkDb!`O=CYRZDWSa?-Pl-Hirj8o5ms)MnV2 zh%+$h_-9cEpd@H2r8T% z1`%wY5)sJ&-IG%)_Y%5hRC*SM08xqbl$f@7zbPdt>0Zy>aJsR#Tz59G!yj8p=Zfb7 zEwx4cc|MgP;7J8lC|KV$KczUzQ!+4!YRmWzA4_~Q^$T2jY?|N=mWP%?QiJvq9Gm#0 z7I9-^v<%9!jkrI=VNMiNku^gG$&60&8>dgkm9RaC^C8r)$vUeJgO&$bU(Ty#wY0Eq z@g>3kNVENm0=bD%Fjw#XXr!g$W_(BfH&C)b#p%Q=)=rFD9xgsLn{SqksRz7gV&p!v zHOs}tJ8XIsRs#9xH;0xj4f?HENKsKsJba6&j5E*)>DAQn_;?;NCp{mtoas|m1I8FJ z6d-r1ef?JXDj-Kqp^t=Gtx?ePmcnV5-;x9@Iz){la;>4k&`Mo5u?3H3~BYBB8! z`f&tkn*jl@-&J}avYN%G@k+LD=P5WBhqHszmahm<7PXSX+cBe;%t(qeEM5@arR4#) z+s^2(guGMC#?8&I4W}&9({*yn74;99QmKC;$gZb1FcE>{H21NuV{}v%NMWvD@vdtg>JUNR8HFTy&=I zRs{(ts`jS=cXYiX33#`Lr~>16A9pjQ4Ujd@^)Q=`)WCtK{fwFqXGw&d%Ynw1^4Q)uWXU44U?U4Br^tI z8yao_1$s{;pIV3wvKz~hpcguYh{>4%vjEL1Ux@QHAU?Ea=5*-pFBb__RZtie71YHm zUVLFJ_w%u(Af3pY-)WyZAi~x;gR3X@cdz@ z@?m$a+Bo*nUMy6?oTg#t&D-$)VpBk08Rce;r|4EN2fvK13ODmdO$HkuMA4{CXp#o^ z1qP94-cM{eP@>dOX5Ije;jizi+D&)EnKzi#Mx;0*E_JgJKK&g12Js^DfBPOfV${0b^pyBM+P!Uw$INJN+sGKuYQBAlKqMi1O$44uE?b!ewDIY)FMXgp{W{5$i0cviOTZN(4|^Cbsqpg0MobsM7e{DIdy@$y?8C?|XIpnXPXjlZWxQ@9wB6mn=)yeHk#5`cU(VPRa5+pIz=l z^s&t+m~24F1D2UGyRUDHHN&c}p*>%`1+{1cy=Lis%`*L!{l#xVq0F++Li(S341NshzX^qL z|Kmev%572p?Zm^K+9SQVVNzQQJ-z#JL;G#7d8_FnCN{sbz~i8n(yGbrU`X5Dpanx{x;f-yU$!p+QO^HweM^qKu&)q0_W zX{+2;iG^!=u{gZX)0>pK;_v~V=Cc&Tn9T#!HS^MQFl&!$;#-+DUFc=IM5AUc+z&cd z70j&;opJqTm7zQtf?$PGHTuO88WTUJv=k2D0mqjwuFJ1lSo7Z7aM$aO=v;MJ|7bgl zCA(aBvEMEAB{`U%%dMA*fq(0ZQAMuJD+L-wJ&uc7)>qTzv?}&|;>U%m^v*>L@5)>^ zMCTemRPk^2HYdeY&!m(vw3ZzhbQhQDX-1LLP_3yR>x79NLxt7Yq`vHlXd|S0FowKd zRaWeF>RxlSw$Z#cNhHC<;ijshaZ;#ow9M+Y3nO`Tv(GQYKzslVV<-&`1FAE}ut<%O$?S zV&>uuxr)PWf6c;Yem&}riPDb+_8biX+;fnr;A7qO$_%fO*ek$!(A`z(GSH1 z(v5qfP{YVL8J#p&ZEQvQ8}{vdS* zA$aJ+h5Shszhj<@7?zn`E6wLYVP^d;`bT;EH3#*yyw9bm9wj{WEWeqG6?gD)NB&9T>?R8 zxaYyJiA;)?r*Dge;msShr|V_Hx`HIN`KC#B8x`jgTWQ%03}z}-M!V-lFDq?&-5)kp zPCA7LL1aAdTla&ALzPdm%(=w@My{25JI z;78{0RIVu!B-t%O<*GP zS3HPorJv7Cu~EEOx;S?i*Nhp+UGsZ0+toI&tgia17RAh?yaH{+z|2PY;@J1lnR zDz_9hx3r6E*5tXb^dG&-Bai+$LDli3)mNTp*#*)~-fskAr9X9{eRrx3fz zVNi5=^X?y<3=k^f+OTWJ0u&vRa>noXUjBwL5bnKS84Tllad==NmxuMtp!=NRY%Oq8Yjg0% z+0$n>I~SqHmMLp zzbGX|;5=$-pKN6|stPH4YW#)1CBSWum;ar9=}>sS1>tOLejD{*&3S(TSF6|7pt2_6 z;Zkxcx`}RC`ti2D_{`fJev8Wel35OA^1q79{}A{k$!9=;qL7Onj8+oy;$T$d>nUWh z?#O4>^($)NE`_z!oWbdg?h_14Tu@;Qyu2pB;m!Y-uM6~u|r2sH*ZHmjP zzoUyTH-wgcK;~2+YBkGqn4=-Bc5*tI@ui3lT3?S-s?d|k;Ww5@=`(&8_HHoOm;Y=Q zS*SoMAhvTYXibVAkAQ$+*ezQ(>qb~Xv-p{K{>uC%4gC>vpxygTc-5nfBWWNmVhQlF^bTNRruR0zoGLF5df+{&o~OewB^c%m4JZO zAmWea?MX&0gw4eX1(vVF*&(nBfS+Z+DiL;VFYCU%zWpXt5$$H(Y-igx4t`wSDT2## z>DtcZ9bRAqb?8ue&2m#i@+`prvay80KGxEJq321bd8k7AP!(FGZAFNa>)!|m!QUHl z-%!Ws!&4^_NKk>s<>pRKw0eY&S4hFr{{+=Yh78RZ`~MCGtvndOjtlk*FQqIlZQsi@ zTyrTwV`erHLV5-PCXm1h-g2M+s{qVB=3ZdR{tnNZmf?U^??#^M%V2>#-0;mP$aCMOA8~64(9{ap4#&vAIEUq=}7`&Eji%S2i2vUk7{tmcB5VUGsy%;1;sC$(&%vB%jT=F&k_is_a~hdc@cZD z?|{ixKp5c@q2liDBK|L^gYLjMm72E?4vKAt3;4T;DL_87973^8Zjg?qMZoTX$U*?b;1jn7kphaNkx)A=hKf7k%Hyd?k{ov`r?28z{ml`Mr33)oi=BcP>Vf&W_@d! z7SN(qmyn)EUiP_`2smLu)9Yt4_}E`H&bqrsoDfAb^3-2EXmqyCTv<~?IE?8m`Lu&d zY{?3B&arG%T%2ogGk)(y9Iq?IFM%%|4gRo9bgzN@wVwdfw#)5Zo_!;?k^Q}uoeIFv zy#7ULZtzN5yVktj+$h}~N&y(HBPNFP0k0v6;XnBH&s8I=zykB|Go93&(V%7#$=?(U zWGq5AA+QE$YDfML8z7d>hhmHGPST(l_;g86|6Zd`9*V$BLWUAOiNsHittjx{Z~XX+ zv^{Wv^Rju%-3SP;2vu$Qy-NmL4XLj@A-sb^Y}p3&21Z%waUzLxT`v<+(u^Itk&KmG zlHm2|_=VwX9ugixj|}7mUdaaqQSbEbRxjh??*9c-#L`$$%qo42ta$hTMBy*&a;i<4 zl<|e8Zqf@0qR;YL@Xc)ohC@c0EiGWL1yM|PT@UsIH<$`%xE1@&W~S|?jyI@eWWy$h zoIyH@kg2kIv`iEow-Am;*e0etlN^@3D~UXI=CRb zDbR?3?(HS!O8eYJDt)s4hlckm!olkxq)+`{bSHG$rFU0WJ^$r0`gNX(ZF+S#`Tr5e zLVYd?Z=U{ieC~ssH)`;pukgdz323Mto|}?VKcu-&-MRBdOK@+Eo2!Q6H5LM6FO-{R zw6RPxu#>u77~Hf;d2tB9zJ}EPqi+Pv5c*t1{A-Wf8jcV(+}pjX^8QZ_#?QsE8Ndd{ zES%{NzRn;5<;iJk@O!e!UT#Y|5jY^mL#7Jh|9tzOOeGx(6)mZ(7<$%21^lKj`jvpc zQ?%9W1I7lZg9+CIM56BL>ybWX1brI24~WtSm)j{Kn{wje&I=Oz^HaYCGpm-C47+}#RG=1j4Vw2g2H_|!auLZx8YpBZ9ug~VHl}a zvctFM$`~2vMlu1GcVs3j3Y0ZPm+f-v!n$6E(4S}cxex>DkWEX)hnymhDjCEGSonyJz%=K`rgB+vMQQW1Q!}Y(FNUm2KEK7;{<60DEo<8vM5|qOjgVp zTP)lD&mjSzf1>H<>cos>fCx2s-Tmm=#Q<$@dxz&}x2CEA3h0%**3JO`aEcPOh z!u&0|8p~EWCba-;Kt|d&3Y!>4_D)|f>8~fpALImjfeDU-rN^&i&L4H#L!h$10Za=C z26ui_O%fvBuOr)^3uYLBqB@Oax{n`1^4RB}PWkx{h?vNcj6^MD-jW2YTL}6wLmGhX z-{h5noK|Du{-TlZqA69|yfJ<>#FeZ-19^FrtYv!nBaRjC1pIL?x^M|0eD;@q{`W%! z9ms27z{tqh|FOxaX{=61Fin?E$G6xJ2p?{%ts6)`5H{JTc_c1J(xFsqbk3aucRk|+ z5Cp-a0$~&qv_w1zuV~T3xY=9;o!b1rakCc^zRzQKcXTJ`B;%z!qUHAb>{v!JkvmC> z5LSLA00R#g0aSixt}^(G*>w|3_aJ~L!Wjfwi0_o5{<{y`=Pe*;ZH+GKrK_ix!3S&l z9>RwckN`&^xsgG``Nb|Gx_JJ>7)`;S>iKVk_D|#lJqGg-rX8)%XAd2rS(ywYh#ZL$ zA&}tS%!1k=D1(phmzF9{ZlsL?;k3lkYnN`o8d}N)gcH0Hn7fU*Iu>d#k{~RZ2uX9l z5CiXT-DT=%k%<1w)aH{I+mY?4C?3yi42z%4^v^T?5-JAIFBd!fhEN_M;2-n&4Fvl8 z8vp?yXnWW`hoC+of#Ygx%d!dcEGm6-Ik=EwHJl!G%IS3eX-!^6#Y^H{ zRNTi^8A<9Iv7@b2{LTkONBvU8#t#CR+wugYHnhH2lK2U}Q5u?F@EGp5vw>i5n74Fs4IEh)elg z1qC{m9Ag6@zzHRS`!a_xF3jM6Uazxzx1Au1<$oc-ek!mMH_XvQhdcJ~9@mUTOBsX! z%}egI-w2+m6WCu42Bde(QbZg?zF;8-FU&$dCjfD|aRji>Z{7vTE4bp27ouPejdRPR zaDpQ}hV?JdQFdNyiwTAJWk}xxK*>T6-jwF2xlH`EV-xo8*T;+gf#`oBtIh%BwM9b< z*`of-0?P`Q{J!!9m*ZdSUg0`I46KTc+6bHblp?ai%pe{Ibc_bDySugd7YMHq=Y29V zvndv`DfKDdw1OxCgVYlWO4yPTnVj{d9I`@5yOKo6dl>(61_=LDrv^l{Y=s5IRnb*O z=a2h}>}p2t;6$>K!u>B=Xjxc5#NR2>7#Op3y;-9R&3CdVx}Ey}mK0c42i%)#cc_4P zh`dx<=aJf)#K?S)tU<7MLR1ifz>#i+;#Do1Z%}oZn6J`k#{gmW^Ee;>E7|=M&~2Fl zqfb|ohX(P;&Z@1QG$ilP=L$8XeG07IX6@^cCMW!MzMi2N2*1Yqr z<~-`Iqx%1%yonh#z#JJs^idxI+9A;2)e-CT0I!k!UBSQ0=&q;Q-vN`s4T7=dm~q74 z3~JtpY%bzvyA%l#n&4mqp9z6wU@V);CG&u&Q6t({Rtr!*u@m`6xq^|95DrbfHo_CR zwl`?%bLE@sN#y)=jQUdRZmGuQv|8a^nH5hiV-aj9dBeXvtfKqU5`$~Xq!IlMKvklG z2HelzUIS`KSSXZ5gR`6eqtYTgPQ}`Vh;@xv9M}jZ8RX(t; z+J2IE!PPb}*7_v{SQdaB??nUyut4lDIa2Cd6$Hb%pHiA`aK50lY@&b{x2Tzk4U=?Y zKMJkcT=v(YI4P$r@c7`t@Rvr0>OZs(+}fFm;??-V348prBiyEm1&{ z&5u9}b_Z=!-OCHociY=#XbooRg4$LRh=#VmSH(?!yEKvNTo6nj>W{nF*B|}EWCD3Y zopIXxz$GLFND z0;2SUv=jhSYE7^(-`_)geonhc@>d{Vk9KKPsJj^52(kY@?0@kW`Bwt%hQ%2-bk!lf zj6q=u#6*%yGEvOhF$UQPNFhTm8;Dst&e^|&Ky-}!P&DBsqN3tLhT__852tdjKMxQ( zlek@MXDggo{=m7vqc;{>rSFSqFT~(DWRTU3A+Q#giu|xJfWm$o5fEk(^vXvFA5M4+ z|OLKoQh$+CA_Y(1+6GU3h30|jC+FS&6bY#{>?6wg!2z2Wm$Pmxm$NUl34 zci9jpSv>-Be0(j{G)3hC{w*P1 z$^WGCq!+-6rHs}S|f&Gg^_o}YyvVd*z^uH@$Lltaj#K!miv>B6!8}(2SqK^h? zLjWBZsDRm-aO7CW{QpC(0a(7=X)*<3BW%Q*nWLqHb(Dx80sY%mEBz)k$z%#$2p6Mr zFz@6=)njtqEBO{|cS)H0xKJZ<-LtKGj^O!yFRHUP?_?FNx6jww#_v5mVZ>R_L1>$= z9aP?^Li;6|``&{SEm@gc*w1VcXn8Dla_-g{x(*l-d_saT*qMAm@DdkLceBuHMa>|k z`<5|Kd85sDlt?NOiZeodyY50D0mctd`JCxADn*)iRHERm9aR<}5hsvSuL5L-Upy%R zB(t4`;iFr7(q*I()re`QBIpSOLupww!SQIDl9f##xE2SeSinCjQtTFqbS>0|)85E2 zK~*RkrwB-Dyz~tFpjcH|t2Z;dRbc~q{@E0$IX<$;Iu)(Fse`KQU4O`{mDMq+w3Y3# zXl~svYMLM3m75ev5rTBlEY0}XIh=nN2U=+`KaMU`#{OeRp?UH_Sq1t6IGWE?vtorSore+q=NR(YA7>@rc1NsTCv4x z0BE%4XNIB>umKdol}%Vt&d!}!3@KIL>fTYt$T&#<*iN12NmNp2$}7{maGH_+83{TK z9ZWuQaeX5HSP3W_5jj3i;*<^eyeZ9UM;kL()7JM5My2h2%Iu$e|4k0EF?6|&EM3(B zu<<{?1qr{ssEeZoWERh9khM{aLZvbxXDGB@{HH`J&D@CQw~ze+80nJBq<`sP40iP` zR9DZ&tl0YmzwEl})ST8n%!@f=pyOf=5gG{#T>avm|M6cbm5i5QQ{=abDe8-iWj+YI zh;aY2V(Mrkgb*UEuEGo~^z*O&ILL3JRA3x_*UXujsPb=`r0+f0pW`XE)!aqKOtzrZ zIg1izV{?RsOgq;Bei*)$jZ|2WQB0Teb;IpgJl zu}y;Od9KBm7!+1qF9rb}YAhWToy&bl;vJ-mWwg2);MD{pWBN62Q=UvXK{)VPiZ(>V zLPF;aP&uZNat+T_pp$(tJ+5S@U-IkM98@mGYc~jKM^`UPGl1(ITA$%T@}1dTNl*h?F+y*m#fSyaS~_Ln9^w=#v$g(V5Bx9GfN zf8^hx^BWue2m7Ebpe9eiAAy4|_{yYdIqF_wf*N;iNKL)vDkzg@e}GJ=#u3xLwYbkz zskeqCHLfvXVHz#JVPuA1n^ip4?X(#GM6@-LJy!W7C_JrUf2D0i(k|u>viXBw$NJ+z zKDN&C;G7Z(Q7`}8$jB_W;(X;_xK5yDe0vs17Pf026k6YX{N!S>J=|E;%5wL->gCBU z-`f%b)tOXwojKDUAp-Hp#y%1uNCMt=nK9vbS?j$O4mb_^MhfxVfc< zg*XHXtEC>DDugslUD;BYF6^bH$dRj!>B$aB_${XA^n`(Jy!r~Fm;oesB1kEa@<9Kh zlHPkyZeq-7`Jq1vZP^3~9%M_b5MxYa;1@HoKhf1%2&x*K69{Mu>gcJM*Qa=WBOpff z(s~Y(0b6+BoH18B5KQ^HLS4kb$d@tWaEn?c3RgVVytPoMm^IMNMm0)wu*9G>7j8vY zbim0ne!F5|-j{#d^_Jiqxp(!!U8IFp*IT;Fo`T)+bO(kTb3LQ+;m9Ra`9v2QNOcZL z`RT<=zOl(0R5x@@H-$$&z4(^MYCIdP`(M|NEsJWoNH1}G*Z z*nfQa>(k4cQeq(XKdo!|3`*5*_siL+MgaP4Mg`@P;%b9i)M>Z}@}uMkU!FuV2BEt! zv2P|NmoU)}e|%QgC_i+`n*WiTS0aruvkotxlS@`-8YuBeF*E(8X@5OL;9c537eR(( zFi_7Fa8(NV7yFC^8s%r>UW|%g?la{^fGlPJl?Ou;tOj~ibn@C4TPXUp&!yn1#do*S zG4-_XyzyGSDfNyu<8wbyK5yAGU(|ZQf20GD*7?)Qk10i5nEJJCsk9g+;h8!;k2<@& z&|fjJBZ$CPJ$V45xjHgRFk7UNk^pojIn&G5HMTU;SuHi`v-F_>7n=NqjDGtkpzdyQ za_bq8V`f^)gjY`U+kK%FGBLi*Mb!t5CwoIA4u%Y&20QvFX=sw@>RWNmM1km*-9z0t zW)!*cQyG_8-Z~*DAS`tihd|cHkIGPI%eC&$O&gACu1Q101@I{n4YUj{hv2nlv*0~@ z9?qscIC0+4G1=3HogH4%d>rPFq-vqP58Z;pK#oxHr63$5(JmE0g6KOi8n?*I#mnp>GCI*yZ=hENV7pvnS2K7cDxVD5=n4XRFj!ns}kA* z1>&}J-X{2?TZR?}BCZb;tfia#c+vL0xs>*M;D#Ev`Qr@H3KoRCPgDqn*s9?+?9D9? z2nrPggd@F=hZ6h=oSg~m`|o#+b1O-V=SI}9 z+tCML<9yR-!04qQ_$TFL2@=C7rV#rVq=x9{QR;CVw`wpw*I!@J^`!SYIngx@2X@@O zb4cbvH}9qr6M6$geQ$BRhBv7zgm;Q6X|_#5p>O9~ux$3g|)VbLS5*ep)|7XsF z?-(AmNOF-EZ{APqG(@EqXs`8DvCL`tyS#zmA+`AkoMfhpj`~sv1C>(&_?`bOOamRG zE_N1@1<>7HTPx7&CVhmdD?^4p2s##L0<5rfjK_ z`~HXDQxRU)?5Dq0!fa^G9JIk-#ohY0D?WZ@OfDQu6x;e?E%zw(KYfLw@8Jm(hcA7y zlkwkL#&xIgyXK>~RLR2Sv`WRCxT7O2{u4CM65dafB7AzXBTr8?MB1Kwg=>2m5ELM4*?|iyy|ZEkTg9+s)WQAGj&LUoLRt%`mpIv|rkN~rJv+Xp${<3FSYMD5>k+2D@3Mo1 zQWrWITqUqvcJhJKWw%2!b(duh_ej1QwB71bW_(^iKA9Mw?ArId z)PUZ%J7^{wJ!oq!kA447y#Pt92GKJ1upDpBHid_iaSZ5a!1#FzGQFIttJ()H9{^}X z%MBXnS~N40YmkJX3aY%+fu|fh~c6J8PIze!8Yu zi&nY68oymN%Tc4#P~ot_mXBXMa+wW7iBJZ4)?<<_aU6HNkuiG7z0d|lbkZ%0>7RIO z_`usV2pzo549%O0^T)9##=%v|x#hc}KE;9+kry>|oucA$y0lBCzJVqmBu_YTJ7NST z>!erL2r2b(afq~->}m|w1A;EYF?+;a6BDSh!$cOqEhD-P4xBaTa|})84E+3<49d*Y zoAC~(1&7lIHPIHT6{gCWZlC=ym{?imv-pp{Hf+_o9yD<+RP$JH)NJRvA35Oj^xkjQ9QU_B4e=~n91E3H_Rdi%TomV%8(FAXiZ7oG_1c-M$TPdC1z6La#PeiCtOfob%O@Y zScdEC88LRUzI;7@*-$1x0A$navF~ni!VKi7;hH=rbo11&D0g3oi(3uG=AM~eb1sZN zKMCHUwc~#)0G~G$8cDIiO*nxQthX`iN&B3BCE%SR1AkAV>6Ii!gHJ(3w{Se+-Zt~} z^xW!aa3#?sRDFs=dw$f^IhTz|r-83nwV&0qE&QQ|`XLs5TiN(_d;Y@SR@j2wdH^5; zxiwvfG4g%qSHF!?#1-e+1lYu6Y8(YA1EYMH!>*Y9#ZxWvyml5Vb;-26_LALi%$VR) z-@B|Z--jvq*l-d5FeT}itI8+`wPb-;YqQsQG=1#tHA_@uD_X--`qs_<@Q}kTBwwZU zBkzRMxALuuolc*|*xaLIyjo`|4I)j)<2Th?p7EyN6g8c{r5Uv|8^>2T2`^zUamrP1 z6BLQby&E-da>@V~@zmkpNkPOqJ7fA}D1}JGi9(g_!CVPN^+|`5MQTFO`QXcweR}`K z)hOQPZ%3rM2JcQLu2;`pZym^Xo;q zpvwa?q3~Tf>mF>6T_+F=vg9B9zP>)Y)$O847N5nV%w1@zJ3aZ$rhmynZ`sl5YIooK zWjy2c*@ohu>FMdELk3;V>Ej#hE1l}DKQJg*5Xa}ll%ne_mEN-b4{FInue?%KqqJ6H z)LBhZuvQ|&mH%&#{~LhP-Xr%5owT~P1v(vMNTe{H?DJvslY{E^cP9TjkLe5CILCRVDBuc^+cpyHTWzCZvVZm|qq2RwK#i>ZqfG112+)Thp5Dcj z+99RWt;IT+id>2jr_5Z#4%=oS-ngMDF2lJ!%9Q--ai zA~JF&*Jwnyjh2J&#y1<~(du}5EQTgsH=@{dFRx6G^a34o{C1*vbm52bhZ!lJ-MMx* z$b@S>x%Qj+%tDO$ZGH3S@h#x&fLWHhXD+uJ{hrsx>d|7B1Xirc?~*c~-tOGq7|j*; z2ZSyCvYh8l)~HiM2eq+UA}1^yz-!0pc+cS+yBS_Tm2sB)~W& zOa0A~+Mw&k>5m`PzptKUISxbon$C}zg1lL{m;V%1d5)O7`RMpGsRseaN_Y}{W`*ob z*RlZcQsU{L>cxf+4|t9Sm4Sf%C1)J0oxpC-@e{3 zFq;o^1BcnSqpP!IrG)Yuih)2FyHG;^DKE6lUVH(8FN|4PWwCc;3`WJ^)OBKaoi48n2NK1CR3hgGM z_JYxwNo8POJ(Um~c$v_`pYOxox-Qq4ESusZRRsih=m7>g6O-(xH{GC`pi7fDJBL5z zTHPjgZI*}D5_x|FcU(`W>ZSl#H!ZKIT<>`xhCoYBVobYj(LcUns-mD>;)xJ`MS z;_0p{I5VL=8atuKE)JQJasustv~!yb-FZ^tt+>-e~0O{-;RcM zP=@X?z3#S#VcEy~y4G$)8{5=}A!O3kK-F_&7Q}cxYgB5;U%ef09+i4!u~`|rw(}80 zaTB|}1ZucUo~$svHL8`a5)`1is-LK{Z?;yspD*_NgtMVh!#(G|SuKwh?RvbaZD&b< zXSZ6N(Ln6E2*kRSofLni7o}mF9>vwie~Yr==(c>Xb)2|Hw%7mXoy#O z)|v8hZZLXmoAF2tEl2VW(BK2XR`{sGc(J@Sjr`${`TtGH#My8;bS(d=&mlU09qWw!{xF zcOK9JmF7Jb_Vs?0+vI)s9^EtpF(WG%Xw{hIWj*L1e#H2$yJMhWirIsf$+M-oVY`OY z0o`zielIsi7ncs}%9$Uj+uv2S3Gycj`r{b1x1)?MlY^Q5WV?|DPl5Tf0-5zzw{=i|{KF8iFcTUntilak)YCOxQB5FZ*M3id z6rTchS_eG1ds!l}d$xs%X6zG2E6WfuvfYvf0FE%jTeCqBHfEmf6>fd~^{+JNn_$!B ztXhih%0ji8ze+F-FgHpWMpEv~ZR?2oIIPgFD}gpXj`nikKh7~dnslvE$>`BIEDCjQ z1AcdF`#cm!x6lG4$Gj?S}c>++4eL z6is`IC)HWFL9~kg6cFfM-gr%c_A=(11aFgT0UHRQ)-1<)kTY{d+}Yq5-DCNvay}Ub z55=TyV;JClrK|EUY*9rcq7O4Tfg6OxMX^fV0ci)MzAu(*1h5!%@$E5!U^_KRu@}8f zz{)XUnKa?wC&#_D!rfr@OTys-;Mj#VFG0t&WaQFCyl&UW2?L@XX#nxczb>so|d=1UbE>su({KxU^`ttm_ z2*g`G?gCyIpQNebJ$qr=8Zlqbhn-S&P{LOVWfbdeLRdTZ(Yhy=uZV(k*wL~UH^>U;(nu17XE zHYIp;;ZR&{+YE^>)u=nHJJ&@mZacGf<4u`7@JyPi;D=ncpc-y0C>HQ(BrZ>f^(X8T zEvsf(dUPu(&s8#QFBd}&l$R6#ouo6y5RFXp=R0tO&&lvF|63lS;BRq<;Y6#u>Yv5Y zMkS|MbrjlnROeL8JU4HJm{28tKv!U>@YpyBajdyiRh@W&R!ZcEA5yFWqk6seZuJkt zTW<*wS?ZTPnfrNz)?IHgNtT6uSZmb#{jZ#JJ>*51JZ~ zkH%Z`a@?$T2)!}3`!p*_oYEebI`D;20i4^_J(f5S&f*Q5XkPuRmY`0N5&81pg><~hl6!W*S3ABvvpCBToUVjbp3!R5GC}YUd}q~hK%p^w3T)& z+STwjOC+*k3MAp3>Yr?_c&YhDJt(*7 z2ga&#B}=DpiXPQ$D}s@FVs-&*I0$0zL2gv?r;N$_rUF;!gipxtK~2ng>vslO95(y8 z;1YC_FB_cCnaXMm>QQIvj)0sk#GS8G%n;6cA!RCOOaa&BaLHXjJbYX{53`0Ib&bA7 zR)Z{lVauNB_`e%Ra#-#M5_Lz^>oa5k$YnPLKK&66FL`C$Oc&qOw8-eR@!8yNf5Brq zWju-n3AccR)S=++bT(Fba~s}r$fjQX%tRJ)#;xZsY)JO*sx>ZI5AWSFP=1a;%%3ok zbFAC=UUd{SFH``(%R)=>(nrFkWaI{JPG#o9ui>X{wsGS}B)afV-USMrVdI;|W#`SN zLbzUDUYTAbW$c*~w^y~a7>Hfi|E9hzJ}yKyXP$l>;kBh1}(1WWEXGWxuE&z@bB7n-~l$|I#@6ngZLaevBHo&UR zMDA@N!4F&uVs}~-ziQpEUk^7}(R-lu(5S)XYMV=UjVoxg@!xj2j}eW)VZUC!9rC0$NIqj8EOAy-rCKXC%X76Q ztXXGYUwlG~KJ1|S`qlHJ?^j_-xhF4KAHU~lLw>u5>_U7-PgpHkYSg6yJ4sZxa}ZO_ zRIaXdNs)j|-F?g_^JmY#!P}=sh@vnn@l@n|(e_o;;5$WcQuLA-sL)h9Z}SlfF}A-0 zmju6*pQySyLZ({?K;)9E zM@z&``I5A#5qQRFqBpz%p(`$G%I3pnz~O;9YeczLSiks|uTe1L_T&}*n8qP3^fcd( zpbbBE(vecp*u|J5Y=+_0xzV<_(@xc~;LmsEsnaH3|NVPeL@`}#9rnVbfG^Y-Fz5(- zmxUIVRh@Y^UFTS~v_C_>`i`I-fycXn+!oL;PPBSlgE3B;`*-&6zW;ssW?_cC)y67T zQ!U`CN12W>&we>yZ|u!~zau>HgjB%u8Lb>C$m!52Ur^LoOf26~^Jz?$tmp@$KT~^~ zW$V zgx}?P#>(3&d`!=a$oU=*Ew1Go^VR+mGnOH{IcjrOHYol|H1p27{C^Dmp9O%W)O)sn z?ne-azRH07Z_)A6d@T`APEOP=x;nPfeok^%SUFb^UH!d0inU11kQ5evlr@l)QQEa@ z&Ssix?eT3um08qHJ)zqk&b1fV(9prsn^hE#bMJm>z9PcK;A(;0(gJj-Nef@I>ch7m zA@j@YP4C|j&Cq_-p6<}Z*6SEzthmNx?WBH>0sc!^L~b~Daa5)qB(FH{>jV#vQSak_{@3icU86yC0|kK$(cWmut!9H}A^$7v^S$5ZPxg--w$x011J?Loh7m@9 zJzo$;hq*VnRs4@@HJbbNZBP8J+6axCm*C%U-RGNc`P$V!^_$#}7;8cqB$|_X*ElVgX6*?)Gci z=#!IApXrChUvg4Q?>@!C5;luoMhKS}Sl9RG4x;KMwBA~nYe$F+bc858*!X{$=g%Wl zjeUpzWv;_kHS@m#lCFj5n#&5sMWX?cfVFGv&~}5;a?Ea-4Rx{u6HhIC}x3p%(7Q3 z<*rc0{y*WRlJMN>q9dmm zBs21rM*{Q&}vfYDJZKcaBP}wtAnzSxDJrjGJt% z-AK8-Mvzi$ozHmV-89-%)C&{g}|$G->mM`D`UB{TH;KM#(I zp2TlQDuI>IOJAW!)!f`Nrf%B%%Rgtstm672)Ho-c9U~O9xKZj~#ZijRX+Wy#TnPhc&G{->UK%yDjw+z{1xq{E~ z6@I9Um4B*?wLO`n3dX`_h3@WH5X5o-dp~Sb_sSne4kd*|NmaF zfQd+IwulLPR}A3dzN=r^xM&M*n|+=!|HU zIJ?JW7;tCgs@O)=praCNA3;u|m1^aBb#*kyKf=jXT!(AZ+FN)bLpb{<2Sea|i|ze6 z@paWxjN`Ko>LI()XJ4+a|C%-1wq(st+=gIf0kBLz;6f-P>YMt%u$LL}BqGAqs}Dmk3MLx+S2>_w^5Wr@ZiOB&#b@Yl#FfXGGdm}TW!qO2D;A@lNN$D9Fu$p0;RRpt@Tyq9>+RPd|TMvst(paUfCEo zO}R~U_HXQ%K=nt>T5Qw3ej=zl@O6A{I`rn}EcMk^fT}Hhe&)zY#nHer>imsK{CIxV z9}G**y~bQNLR;Q#e&!I8+`vHw9vnjn?6%(*Y~Owv+(aJ^4#l{hW~$0-YDOI+cpU_- z6Ov$+!Rezs_Rfmav$Fa#mv;!dlkqk__#KwME6_a(;5F1}xFK>IGrMD&w?5h~BTTL* zAfNH?BqSt%Emq&nz!zw;rl#?V3k$8Cv}|OZ^Vuz*y17-8n(1Q(nmZ$VA0+xLc%F*Y zy6xC6xbduj`V1R$VwRvo##Z7WO;+}sD z{xChwsgaVO(EwFTiGt$os~~{;<}Uj^=A3ky>6;u_>QSb!cyI$TiG8!Z&zTa{Pb>zk zQqmG(gGZNBSuRIhiDTPfM2JCV$6A(n$#X-|%0e23aZW$PA(g^O@6TlXF1>okvcYX+ zY#j#hZ)`aPKKWgmCB?;aA?p-XI;$gW3iE@(6N2-3p+Ar~_6W!n{tw=N){+m1YM9B+ z6ReVZ{u=Y6A~Xx3tv(2`@va6bC;=rRrlX9jWSa#9gFBAut zt^`oUE-m0qaD2O)uIMdS${FV|mvP9Qm((ezWx(vp6fpbk@M?+9-S{aI#z*UzkhVpfmu0YayEL6g3+2YWN2&a(x*vD+F~Uo3|nmLqK!=+UPT}C!S2SK`CnX`O#hyhiq8K*Px~L+>HI3tm5+B z-W^XX0s9vtLD+-fldJWNLU^yqwYTe{QnpIdU>O!;*aK#y#W!{(N#)?22^sI79ko@i z$(3pz{~a}wCZERUi>fGa_u7z-?7O1!L$J`b_1(qKP-so-nhgGo7hB2SqKL|a^AsJd zU4$FN78dkm9}?(&#<3#t<&2Ymh0s4<1PJtLiBDX61Z+;b3{&fD4jI;C$LZ2foCa7Ejc8*GqshgXlb!~}HFx!byg|zFDM`)uCs?J)Dr-`$D*$`>OwF7i- zPQ}kgJ*YI#KT+5SRmo7ebM12cFJJtD zsw;4dM&c&kpf+WNi(Ec~#%S=Xl~q&dv-hIm{s9=~_I7#alV&X@i8{I-N1|mS1USEG z)}oKuAEP3hBc1gpS-SnCQ?2iW{G8A7BX9>t%pK2W$$;pvfBQxvl1*{)L797c^q~dI ziCcwY>IKb2ge1nQ?~54Cm^P+T)ERVP>{HG@>k0K zBewJt(*Sha#n988{)-H+Tb@6Zh)35JnZcPzb@V5l$rZT}T}4FZ!P^J^C_I5KO_~(= zDhwu;p@zw*Gy}sxvz-xJ4bfcxt%Sk;O3>^O%m*9dCcs@n8F0YOjRRpd2xVCj5()-Mam)Y_;qiV!!K@o30FN>=k5y)3P|HCgPWO#R z`x+2X>$$4G*iS)&YTHSHg62r;Cv<)KF@NkE(ktEbk>}Q_qy=X;-{T9`EaiS{AupGW z>E=KFtbDXO7(vLLfZy(HdRC@s_cDeu)0Oc^RB zF&cMD!%p`MTboTiNJ0I<(x1~Tk*Q@+n0YmEN17r}BfsrtUg@U^n?Bu#h(j~oKpDHv z{NL}RKmoez$lV?-yCK%2N9Gm13)DM2_QVyy)i5Bd=0SvmWc_Z3yA=8@?qt;~QEQeu z_ZJYgN*QPz8QjIkNwVP2Ta{gxGs)neOeT}j2-?oX5lem>B%tEY>+x(+Lf5ULL_+RW zpJH%yb#<*zLcg^Pmw26ddzKprxM#miTwVOf>C@OA%O>*_%hEuz+oI+{oSpCYq&KIK z?Po6$ixJV9h`~cmMnYT`2H6g!u)(uy`NV5T6$oOS)dPY&Ib&WR+M+!*O zXLJ{iW+kFsGL^JD0Ww6{SbUZ$$2BA59BRb_*=F z0zDqruuEAQpjr!$Xidf|RZvFmpbaos(G$nf`IDm2^!y{|9|$mO#}mGuqq~GXF)S;0t7#XG;a;H~@hdr1MfU{F*~k23I2c2h@( z1mD`ug%&CI_oo++GF0sm+rvqxx0--^)RCQG0$+Q?GB>7Z$TyKLf14_N8FPsH5ofvn zZ54ZC0+p(1Em_2RjE1)OQP2kg3kyqD%EBn;0@9a@7HY3hN>x}N4F%5E`?{q zhj-ovx=HsUwEsCI9vB2`KxS+Gpb!+90^mk{sKx{*B7d!ZcH z6;o|b_=>uR3FSOaJ$$+A-R?ULw zX4J&IPGn%9c$ufY`EcsZhDaH^CCTk2tmE$9cJOvF%Z(DldVtW4W+GWPdqWb{7Ol_~ z!QEwq;s??Dvr(%0o3xgn=LhwEVHy^{2ux-1CW`Z?(($?$bxHxvI^gcrnfp!I#hvWq zW53otUw&TJgmd_a$91JdVz0U4C@YZ+W@flqIz}&L<@j=~@7EtNar!^Elkfw8S-B96 zRrttp9ND@t{gajH2N+ns7{<9<$4D-Fzb$oMrGTpev!MJLXGlD}cPjDQxk zae=gR3cs2qG#!GbXFaf&lQUBjjp6;3HWHC^@S_UNzTwq&7Txn~^=VN9dtYeVSB%In zDH9-WLa3wvW8J&F`w?whD>sKhbP~qRZ>IBcPxu*LQ08mH!$I#!H%2MGwZR0^-LY|@ zJ4U5yE1VXpDX#F`0EYx8^!Fisk2Y3i%NOhT?R`CyeT{!)GpldHhqd@Kp9+>y^clNR zXCGTp_wQGe7ZO;q*HaEYEsKVIhO<-7s#dSCFhJ{YiWG zS0n4IY?`EF2iU1i9WHw;VR|Q*yIEcI%o6!G0L2d7jl-uO#R`*Dbcp#h_1Bn7B?OBi z&Y#u@<-&I%Vg8ED=XzG|AoZ51We!PV%q|Nj;pVvb_6u;G)teEcpD7*oYqAMLj<;)t z9{W?%EPW<9@99jZg&v!C>RTk%JLcUuJU98@3HrL+t7&$Hs)0ReA)DO;IJZh$nza?&$Yeg zz%~~X0A#s=E*(Kw!D7A}YUC@ladNBml-P3y!Zd|3~%9lXbQKoUu?5EcX~@K z5``z6;zuZ#kG+tESoYx)zWnn*6y${pirL*v7$Qq8!(#=Hv+|nXVlvjrQ{7r|xXfKO zp~d`fllgx$o%rnbVfUe^fA|_?&R~xkHZRJfx7=GDCn9~w^YOIJGak6_;-o3t6_&wL zj$bdcO-uVX^a;ACcaw41`peX!IcgP33PXp%uRCwcjNz(TV&(@Cnrv3&BlK*z_i)&_ z{rLE%7Q(h?y#Zv6kVSVABEb)JmHN>O_wEM6GXwFZNu=_Rn4*wPQOH4BveruhqF5sb z1N>@+Y%H#)l$dS-3o#N#P}`#XH}WpstVtJcS~VyOdd!v;K4$SowU~&{g6`cZ*$|k^ zs_QS$pg~lpA#W!&s~}2Qww!Q*nwtS|KfJ-mJ?Vo+QNbrJH~QzH%8BJiD8ZTH{dU_L980y<|1-F%%FGk8CbgnvmGF)J=$L0mz*V}I zAa*LClQz|Q(7uOQv?Gc<(#|lD>dXMa=o&-!NxXOIi;2EeKj9eld8=e8Jo_ED1d}hHXSme7sE8t8#m6_;w&ciHsig2%taQCb%QC7{m z;|;(gTRq(vOGzH+Z(%SP_K#~w*HlTa+a9-!j{Ehy&$iBF+1a|?NFAH!=zx#}yclR{ zGL;wi!f0`OJ8WvCo#wM+q=4X(E5@Ih@%aeF2 zjNhZQcv}{`Yd4rrS&hhW5K-__lIx2IyGCDs9X%vZfg3h9g_W4XS3`sY-3yi}JD^owp?Sw6ePB&f$-=(czH z$;~Cz0x4_fa;+SHcHGn)CAn><2#q!7;!=7S`YkMoXi`WS|C?YMHUL{B(_pO^{Gu3- zz9GFQMecdkg^Q~}9>>ia3IC_CYrmo7Gi3&vz|I#H8~hjby`5y3bbLIB1=Xvu>;tj@ zJ`z|lMME~G34mi1j5Bhp_xj#y3m1s?#_eqbS50dH{mDEC6FLIgyA$~Wn$#-R>=>m) z9G=l&g8=={4ObqXlM6S&A)&3PJ>zEUab*;`Y^Hg$B2gj+3cmAKOQ=MGM!tE)RKr4r zmE&%5MbY|CDz$_N1+=a-m5aBzMnxc{GF)SNNe@DVuwT(LZl|?6-a=>4$^je*L!HTQ z1Uwc(Bw#Hrdkth%R0c|EG3oLJFHYN`3`#a`a;uxPC}>el5~>Vi5;Y#>as%?8QR?1u1_;Vy{*i zv-IuDNOGRX1J^U$&zhrcV9Lx5*R{Ggl9;8@ZmUQEP@5!E=buU1@aj~7ygPFoqA!k> zz0UQ#Kvq?n8I%0rnxld}B0^9au5KVcpz|>#uj(syUJ0$`rfCgoyrSA$ye3 z-;;tH>W|rnFOS*ti%4zH*J>FK8Z!p;R=4_0;7L=1wboWJ7ZTI0Uj7FsAVWL^X=@6> zu~OcO4rU0{Mkf}(CfGkXXaY31maRvjd^Q@s(F<|1p7wF84pW4ETL#q!K2dX)PSF9z zkW;H|yX&}h(?pv$OS4eru@i$v5K=b-Ngc@-)d%%IncjAM#X}{B=mS+M;Ut=UEcyjT z%hcab7`|_lt&bMrHs&0i&7}po2Boys%|Ue%hD=H-Du(N-sAEM?n<@=YY|)cna`q!r5p^Jc$uUJZ{rGt4O})G3`H-b)9E^vU~sd1T_NgTc%=N zH-J#(IUWDB`mVeC42NfVI6QY*I%cOGM8Ia4oq1{zYbx9zXks2E;FJX%3fGHcV_L{u{dbJSPTYLCX|z(dxdQWL>)mlC?Wk?8 zLJX**B4&GLV;+;~!B7oj-N^;(ZTljAy>G zt%A+b+vc`k=+%HEz~UQ^kU720wbBiagPVdQL(QCq%Ce(6;&ye-H|?D>akKjk_8Zw_ zix=!mLbFfzLekQND`r!IqtterG@^SMAUz<-KhQe>iXJt_DjM~Ayc$*&{RNXYJuP8 zmOS4XY3nwKr6mJN_HgY;+-C-2s$;ZHmwE;?^6eb%)z!4~#FW0z--)vzh@)!7@-_;P=tMVBMOOKED z%8jqf9V@-j-m0E&2%HzHts2XlE86Oer9~?yq7AN*m*&SO($mtO89T(dm;iAK9wod= z+3f@h7(`bNU8rVOR>R(qnG)67Vngo0;)i{ofT#_u&?kW69~`y*zbjNWhTT64M8bie za|3Vc4ji^+CbW_bJ^Kk*yFKmgU7YTCzSp`M2+%K}Xq|~$iQpHYnjU2;XCqQG<#~5j z_W|}!mMe%`S+7a?znjB;Sm^rtOw99+Eni|1wsOu=HmRbO>rzs_#_Ho3Gs`Qq@zH1W zy9*hFXaFs1jz0G0_I@W-dnvW#*6DHsQ}ORK9W z(^Nf7xHFRkEM}BjFcLX+Tbf1RT5fSC!uc$NQUJ-NzHE*oCFsHM!Uz(Gr7>Mgu=ywo z!4p0ul?n`v{G!}3l|x{hinlYC?yf*~SewW|#RdDWe%kt#yKEP1Wi@S*q-J>@?I#%= zCg0Zki&GY}JlbEJIW%_ET|*iz^BvnmUyRP1wDtKD6k))MKDrqGukN$%&yDquk83*m z1l@}2VPpqh?G-QHav|5K+)0@jdn6&D(j-fK(=LHEWl%VDbr2l{k14~R3?u0IzBBM`o7PwIC=HgP}hpLi!EvHrgXC$U2 z!wluq0tcR)yrL2w55_Pt`mMfd~{ zduKI|-~^wk=NLJZb08s20-Ce_zsQI%f)vm}SGMwUSvV~00@(n$>op*BYNX_~RAQ3t zYw>&|pI{m2;GD>Fdk`^vfGzI!iU`AB1?3Q8bd?JG!2-aM8{F9j1-}IT27nYK&b{ zh%GLtdtQ9Cj

    iYRxzA<_vGi+r!{7SO%4zD^4{swki=dafP*A1jcz$B(>Y1+mYl z_a>xY2%*`x*%Nbygj8`4Hirk3+;3zZ;o^qv+LrnV@XSOs#iM!*S5V8gPx6yHkgEp7 zxJSSiKh+=3XL9*x;lT?zJid!*2lV`CpXwI@Vob?D`7Vz6$$)gj7_s)0^g{%Z6_tMy z)20op!%z}2?(U6rqE#JhgC&frLfScXuIrOrzaCQ$m|)y`E~Jp}OdY!FWR5-SQ8vYK zd#wvImvTycrD3Jj+1CL~R-$M3Csj_i$lQB!ns5g?5EMhGV`LwX_q!e*^RUvDDeS&r zr&Mku6Pt$KtF-dk)&F`4^`z43chx`HV=Fs;H0R+2&1Zo5-cj={U%*ND&XQ}Rp;;pp zXP2uVr?M(TQc&d|GF7_4r-+B}VJCExr3lrO7HkMy=H;vQgk+~|SI)yrXix93mG#Tk zjy&y?6U=CakV;ystKq6I7aKVKIAr)kc~w&*9r@*2tT|_`xn&lK|Mh0!4KBkji>fNq zC%iE4EbQMPcW-=6;Q?n~uS2a{#!X=VpOhUwL370ZuMc+IYM?zXJZX=rUjv{v_?! zxcjzuxX#TGU>0S>nJbi`u-g@6{Tl4yarPBLt)_+>I1ahy6-fag!~qqeggujg$<5&6 zUAM?Npw_h^MO`C;>dHt1R6{kB6^krRph7ninW&G?Y3hA+D|YFI=fLsdjU`ZQ?8??*q;0=;{n= zHWjprzJSg14-(`gCEq#+=wfgNaCL^$noxE9Tn(A>LJcYBOn6Xff2mV;t>R}gNzMh=zg{(C#f>O{qs z9jR>R@eM~5^*!@P=jxmfJz)JF8^)h(Vqq*AZ;^a(^WSw+nwH))DK@lB%8TMq5MoY= zESIZ+e>G_>GHKa&j5?~AG&w|>TR`!Z^+}~exzm9prz|C28X|M{@_s0PA+m6 z{jA_rKBy~tjo5L8O~b2}ZIq!($I`MNY;7s+?a^(|f4T+rc928RaTe2=waq*L6lj1} zDcP9-C$H<%f<@5Bm(@WR!st9r!@_pOnM{id-*D-k4|rjS$Zov!Aq`-HHawpf z0I_LK^$xMl0J+-+ZQ6C8s*YdxFWwJnpCf-2R-K)QKG(Jbi5A0Ol->X} z2>gfaGmQz6%q}Vs*q1)E(<5=3e2HaV^pms$zsN^;6@8JIcoh@ZfnpuM#zGI7$I$5L zu-*K?03lFHa^7w4gIoU zmRSm)QLxi=ekQi3OQ?2-IuftY5&x1`g zAP2SR2n+~VoI|A$x6-OpS3eZ#SoBBzYuuu-vc8%QnX6ioR&(VJ#2|^xWiv@v{RApo zre~lpuOT3;OgYi*Kcv9H3Hg&!|JGy%7~xDbac1PA8+?OkZ6@?Ok}TJxH?DysA$!1F zXnf1#$jPDA#Xoo4c}m985~`-6k_&essl{KFMFYA$Mwxpm!>rka%4N~j%D;8I8<-Se z->?$SzqYm>!0_4bN}!PD(#WV8?3d^mW^^J@c}Q2F3|(l>=f? z8Q;#7S?K?`gSlP7U~I)YE{a`ip)2#@~G6Mjz^lYwzqoa~EI zL_ZZ?|IWyfz-I=}x&9FA7(*=Vkd&})o|Gy?_L@#lwU%pHr+%Co?>GE4KkY3lAU(ij zdhE>6nE*+>IG|ChbfX3DO$M>8msSu<$@GLgW19@85WoO<8LlYG3EOOdzCS7@Fa7(( zZ>?5Au@R4ae7<^n%~DbI^Ju;a{D`;l&QFn6ZlQNm(PaJB>Vj610Eqwv>xEUE4JZSg zg#x>Bc?z^WDucf-Q73it`-LcG<(8uy=s9)?-Og<#1!9!8tf|(z=!4pA_%B;%qkoxP zUGsa<OPxpXry(g}|zj7*j|p`&0(cg)VaKhZac#XvzTS8g1;oq!H|UoCZkMCXVu zJ$E@td-x;T+h3P$b;A%ikF&Bt*1AYDo#AEMwjiC zQ5=}}9H6&x>bo{Q>o1{fSULRD4quPiE3BCg2PWb}m51}nwMjTlZPNlcUS_!kG%gls zk@BUQIv0Wpp@o=gL}M&%jI(p%%GLrmS6wL9#%Q9D=3z9_?wa8I4kA>IQ7+D<3m1r) zlWYsCaV*EA=l)A@aOygF6@tGz392+HPhuF*_$4~7QVjHG+g-gE9QSm>Xlb^@3b|YV(+FV-{REs1E=CpXl`ND#vt_FbxpGLUfni@6r1u1sJ6W# z(QHdNnfk&soNGlq!r3OvBUyIWo)zYukP%5d*N`2`wnUC7(XXY1f4zpW4pPhYpP@9k zB;IA7pyLydQ&xH}7#ElPenk&i^~=?JWhP#?$HB%WtMSh*({rknNZ6x){Pdlx59dNO z)^S5>5Sft<2ix25D4LqPW&TVb?AYr@cXB$($tn0k`WT1WB%lO;rTayN0m^3{HIaU5 z(38miWwVBK(hK@{)R=UpxM@Fv+aDpuUszUFXg&j$eywr!A@o%17DannQo@|Zw05&7 zz05lZYj3{z$@j~|f)~FPPC^`2NG!M3-s~>>d3hY{B^Fn@(*#Bkg}^CpWbdYgpbazO z_!K^q7H55x^C4X$COOB(6p*N7C^&C-aPaM))7>!NMoKMa#>O_SWtV7ZgBx~x*cb;! zQ)v-vNy&5(&|avdtYYRrhT*oFuk~?RLg*s*+@GzLeX4Ldd8j?nyT4Y71R4v{FuiGD zZa~$-^JfZ^>M56!-TUSX6nD-qoTNRLa;$g4VVv3*bIvQ(eA{O^Wz$n&H79YX)mE?b z)Rp#DxU+i75ESS|G>gwH+cZtKF2iHRj+|yYnpx9~FaALZH-LbfHIzO)UTS-ZYOjE# z*%aGg&eUV}j4f|%4L|Mu4A(xswa5Him-Fo&n15~@%yuUT9C=68I6$qo*CIFM+0u&?HLx^A%lI*ic8dm1&K>B5J>U#%duQlr(khFeksh5gqCxoURG> z2_U>F|G=OwD|rmGW9_80ja`-g1zG~z*dkxrrOutY6vt!_ETRf|$tT0P8qNjVLq*CW zn?n>$4>GbNoc3t?kMgrA#!QC5PCEfJo}!B~zt=~P37g3Y^@jhiy|0X_a%}~XP%jPM3To#y>=zoVzhSqJ4}opf3d0dV4$%&>}JvPXlPP0CgG#T;w#m60~20* ziPIP86EP_~ob;5>)rna@ec_%xS^kt5=%M&XGwdwT<6 zZkZREN*@~;m%#8H<(|7Z>6)zfqwGKaAd91~+G_a%U&yQ)o2X&$y4`!p$O#k|G*c~i|WP-oP)Dq~!jyTkj{ab>IckgGo0dK7@iGDbC&_0QNn}zTz zfPm4`(Vd%!pdh&I-g`TNY!z+imFJ-Q2rVI5%-<6Q)nDE(sWlLSH=k+oMkykGFn}LJ z))sOdG3HZr#Xbpv$ziQmqSVHuM`r^ES&Tn&Cn;cm64r~^)54phDI;xyiiC$L}K*1AwY%TYs&&}|#8d&q~ zr~NaeBBfjQ#;_um`o=EBKQhc`9H}Q(phqh;!>fRPievfNs%`skaf9V~dnG0$>>Kg-$!)|EW#9VijtXY!N zk+ntM*S%c-yt^vb8lZoO-qFO46cd+PsiSr6fSP(j5fpSe$_2P1D z60o;w^Ud|9qh$v!kkhY}hS~*3{%bCv4imVc9;(hk;~QYZF|O-8msi}m@io!j{efx~ zi)E=H&rsfIlq>s?93SyiDY!qTbd^5a|1y1uSV9pTJaCun>!weDs|<@SFMU&>6#} zv|NOP$819iq};4aQ)glbik4>ik(_l#=CGi7rjlee)xE!O(6IW9AKrw!XMJeXOnZxn zH`;HcjlNnUM7MSxoybT2`{|9g;4pjDJNpNF6Ws(xQNYF{x3h2Uc92gP9dRTd9@)bt zkkSG_0XpA0vc85B&B3mJbLaRTrstg*H7U+(uddTuBrr$)B-+`Ykp~ax={>zz$s(b)IRhMfPIS?ZJ%Ui#8l!b^g*>o?7&> zfz-E4W|&qfGV56)$}@5dJSSd>yKsrt@KIv(>V;1Mhj5~BUH4lS1^K>HJ97KM)vJ3?#ilHVhlZ$M z8vnZMk0ZqVEF!@_<#Y+~oJ+IWr;wdZbXIHv4!E?-_0s^6~_D+nWJ2eoK$I zjQC0DVwjMR-+Wgr^9LHsOt$H1(wQV82%Z^D{v`lOQY5C7NvMZyn1K08s_c`4^SJ?e z>sE7MLkACBp~Z&%ZJ>%|xp~N%U7H=QzdhE>GU7`?oEU<`3~F_aww9|%rUe-byU%HP zrxw##5-YvVMfjRAmZLds-e=cZ-IgpxX!-7o(TIr6M%*2x!ab82F8a<%{geVAzFmX8 z4)kNxbSfWd`4gsQQj^`hzuei7`4t%9;+un`6rEwjZ2XPXV75SV%fPYSGh6vx@Q-Ie zx#sKT)@YzyGl#ButcVbq)BGF1OUXyWuoyFD(IsD#&?)lzWuhimaIy!Svpyp`u!|v= zurR`DJBpq}h+3c=Rc_r-OwbWDgS2oHK88#&s zn`XASJ|}&D!s5hGG2EZzv)QOmc~vfY^}+buUcJbo^{ieZphz5h@;>8R@H$}d9q-;V zFp9RP`Sv_nx+dOjlftcP4;=;;mK=ygKeHRwDKcb! zV78xq#AX^m$p0qdDV+q?XL#5ONu3UpsWj8PWiBhq;VcirhBd`mNBSVbK<1}QI??<3 zjjN?(EsF2+Hn?W(v!3e3OtKD{n;I4l-eL5s?Y~+LVmTbNnKq7{s)wuuD2Ww zf6||y5md4Vvqi#$W-Jxo<2zERPjCa3$S8kLbGX=)rM4CM$4f8L`yF;vp<0!4?VlYN zx80}8$4~hh8k*jHEVi%j?Ci{V-Ic?XZ~5ecmqvtYZVeflekmH%s+7P@#9(0fY>*ew(wKWlPnTN`KNF03W;+Op~n;i*(6e*t|xSXsgM z`93}EwU&1?zRM3QEwd#<&_;U_E2|QrX7pr)rutb{+wy|q%3sGq(g9^`&CQw3Fz7MLV9Z;dx~`!@1Ys$f2M4ZH1&T2ioEgLRgkD8X z3a6Oq>5uRNm!l1MuYI2hx2fY~@}44=Kyu%?E>E54Hz$M)E2GOWlBy1ONu4t zORk;xjwWt`UDA{s6^UvE4KKrCl!=wnTME3w)Dvm^DkkvL(#EfXgLSr~7f10@1PmT= zc%kCy>}uo*+DdYBnYJnN$EYGSJh@X63QbJOw3}876na(e6eZ>&Ebhk3DD$~5$pF~+ z5sUV6>n$-y)Ym+G1zj;t?CJw%pz#L3UkcZYKej4`2!~b|PXOr7!Wdq6f0ao1w+49+ zXZQjwzh0h&FKU14owo_DS(8;JqxdlMFfGQDS-)Q@-I&WohmYoSTcPVS(xzbD`pj7t z3ZOvldq?@IykXnc(2!cjfeokIVY+dS?y}jpzHhjB#Xkxs{L(nq`$%R%gLJ1o|!Xv|hQ6xXMZXWO+7T zm-{%S5fTLzfcJn)t(203mAAo=u35#)>#*ge3i#yH9dXv(4ohB94#&;Ax+4h+VdJt5 z(j(@05plk!_MHN_N@c;#9Nh2?vismfGFZ~P1a-a#SEViI_m8b`xnY0AqVI&Cu4!hz zzKmM;W_dxMy@N@;@snCc(`JVkvde1r>g1H=p{%0%c$P#y!>4zL5QEhoX;u7y00E^M@Zo`RJ>w` zs}#g;rAT@bicV5DP*Hw|<8wo7<#B#zn3<7U^RAPx5vlWp&tkl+(IP%6z^EG?81R5- zXK{?-emb?mJAj>=E9SBWZ&a;jbjZ-BwWw6x{eueUr7%ju9J#nMnNRbF z<(axu8om&hI%=L&ri;mf{#F`CHeL2(gkjuWEv<1pDP@r?bq++k-@%-1@ zeRSrkhBwE?x3Gv$51myin>l3a=t2W-I%+2+6cFa|^0~XhE;KHT-D|mjQ03TUOm!c{ z_})*;eTmgzkLGOC_6a3rtAhNwph$;W^)kMK3vsd$E0tHNUc)XJ9zIluW{)bkS16 z4+TuGfCpO8zfmAc&{|DM-fu$AsT4>itU0rQ)r1&e3urK_k#`r5U@TA1t6fG_-aDg0 zU~AE1Fz1l6DXKTIAP?Ul=$Jw}A!5A*gKwOL9ztx7Bvl~#qooVepoJ-&~$6{ zvlSp`$-w%wSh6(Rh!Q+;LOHK>`GbjN5}Xk@;-C|pdm{=j>M+1kGY!@zV!M&WJghd`>{d{9AcoMO|Nn9;oe%2O}gqVi>YV;cTs zVy#pBiE& z4nzDVsmRxl7yI-^7ZlUrOW!w5n||%S-8wM%a2XR_u&i3e?g0ZY@j8N!=zRC}+adwN z9syxYl0n87TfGxfXPJX=Aan5JR%6+vUe}=kn-LBt25E^QaCrWiHq&m+!o;G^iCMjf zteu4W8(QK15I5P4A9s1IHWn2b5hXt7?)3&)w{3NUrz^nt0`<$UrsmWa7~2qUBJ%6K zb%c}W>8QQ5;LGTdv`U{^KAT5YYV1P$mOS2Rry!R$6_LnEd1T|mDDnjR3{@(-$=CNqW4%f;~evF?9S zc>dE_@R&oGf4Q=!%@!U_iwd3T1pXJq06`*^SXHMyCe)(R{QRsu;_+jr6$ zF3>knp1C1BRZj(qj(U-B$e5_%hzr~j^j7TFMrKaV?k$ zk(yEaZ-@-g)XO?`%;;r&=19x?c!w$#9Q=c$7|;qildXz-MWG#)83F#6q2VuZEVAn3 z35qOY$WL$wvz5!!>EJX*nDsMoNzrwR-ZZw32&7-92YV(dt7CmDn|aqREx;uz*XW?M zJIe^QZvLTaJ+z=}$;fayhe|N*nmUMruQS+Lp324QeSiCD4V~!57NUG|=d1X5YdWj$ znKmb^FV8OC^@P60ZZLD4R|#CrdIs(j22$m)$onoHX*0>kQEG59VQaPqg^>uuXtRNM zFnro`#QEF)0Zo2EBd>UQ+Ksyy(lcrgqpRws+}%;rcX8pwaXWNZ3ssTf?^4ryXMF9{ z)&?Ck3DcJo4p@&@Anc%Al%6K=N5H>=h12Wla$6Y5tF*-IB@-JGM zJ-Cr_H0|c>gKRH7Vxa4yornkCyoy*p{SL?8`OwN^yV?F3TY$*PR*{`Xn2KwXR6G0= zyeH9|H;zl*d)`4RK2x7S8+?1I8Cnq`*T-JrqGDjK6oI3%+6}%ID0E;GbWu&7Gx8n> z(>1K#LbXy5dB-17^(CIHlxjF^#s_al{#mJ+!}J`W@(bv_FB{8@W>4E|Nf*9N_dvsv z+c$>O7GuV6$Jp;Pue%m2>x`SM?`&>pSq8DgU^`q6OsxQq#>wKH_R5 zpgoodm?mT7z1;dBs94Bb-Z}BZd;E>&XTd@O3LJ4IwhT|=S2*(<2cJ)z*D6~{gAzZr ziU#`0g`K+WqGQFgQrwhHtTh{!on9OCqt0UDmCgx2wRr-@kvH=5&*)( zuVCY^y5m>M=`i=@4$T+scGj>u5ccPnKkJKh%G*1k&IEG)u8fL7jI4I&GoDI1?c9U+ zdn`C6Pd2tBw#ycy&-CqZvgYnsD2|MR)~B1PshH^^7J%M$Y$suP)HsZRu(n&@tA9hk zuLY!1GJ=kPbWhdS{1-_BzsBkZqM~SSO*|<_gW;{=xSlgnH{Qdx@|8SmSXQmOi%a zZRR~*cxE^}SZ(~`iaBmuSgBudXrT`ed`Prk?U1BCozzso2llqnA4p65w4)1Uu4}ErL;brlnn7dG2Rw`+Xtkdzht!juY=ulfbXRKwT5{mA=iB z;B&=~B5rhie6xY+pL5~_JeKeA-MG+5Svc?n_Xy96ZC4IH=iDemlqBjSd73%uGvp=A z>T`%ofMQ@q`^bVf(r4)4#Tcr(WHldYuvwyCh$0LtHacrvRNSP=FuMtt3 z;;Wpa8Rm@62h;#PBp8vLde_FrBSB4+oX-mHY)Sdo2J^OhJ@(EXid0??(wH>e4}7UY z=5}LC{M!w(&vtCtshG_jb5UWN6LoiA!z0|2n7U|2|HBWPr|MFXPtw*M{XjAPL@o#= zUD&|nTAko^bZm?+-8r4wpBz{d3QG|Kj z5eN7#A85po1!iMm`>K{4ANvO_G5B;OUQQpA#scDm#z@d7qlmc$Guf*5^u*C)B4K23 zS}~vL(P(92YrT%C)PPiPx>oxwTGPw6gG)sNNS6kXD8Qm$smvmwF^iT}T|`9MymVuL zN>Ma;#CsiMn3$LroA0Tlqd`gDsHW+1uU;!sHU-A(uwaZp4SE+fR4h$4^n|%lG}H<6s|8O02bvS=msA5RmX5kkOU~rpHd3{S zzW!~2`Z^0ELJkwAIM;Q$S@CUdSeFtdim;OREa;=$6Ymawa9bsu>YF@E zyHHf@bg?r;mLVw+^N~}Mqcz@VC!@F{w7a3I(~pS!__6Rajkow3>-#IW(*%HScru!A zJCCqvlElDjS5)k^fMm(?AwxLvf{!1K zhOQSg-%-x#=MfdlnX4GtokFb<8%}X*pjmtD1Rl>V0lDByd^|cmlCyhoq zjY%`JPDzV1ft+%L<5Os%OI{2xme9O>DY>-Sw4HH zj_P}SnU^r#xHTGWL#Kz9&phDaCwN?&_K7MEitS{fU99z#U+TE_Bs}W8xbyF>2iV?r z=|U6pb-m9>tEyj9VfuwUzkmbuPZ%S#sOC2#OE$)}KVPVu4YIamLvl=r0XbVZk;ry9 zW)gC)eOGt_+DW>ja&%j{GLlN^>sdqj)gK4cIt~~&n$qp~m(+)FClsO$90*VZiUDY$ zCE`b1c|eHca_5FxOD(!?Ehv)tS%M*Up`}`&>HfX?U&a28;L7gicJ1o|t-Yot>-mTn z($Mx7rjBGFkkMfYxO5c~{)wn+K-fgaZEr3k<#P|^mj_0bz%@lMaC@Y$T#L(>of~|A zFf!TckW{QsyPB9-2s{!E{&LHIA>svlywf!{TU&Tk1Yuz0-j@pL(ZXvV!+PP@b_E@B z9HX8o`kB@rn)CJAZnrSf2>Gq?4sC!7A&^98g$tXCuR~z%+j?FT`MNGhJcL07x$bo6sQC} zecr(GhoSj13=mQOi)=g)sA1>8t$IkdhJdpEdNBm27KBZ_sk9;RSAFu!t2>Ygxn1#~ z+^XO=%$xQmvpVxukD?+kk|7Wott0}d3M}bAY#jP6%r@v8c4eYr^%rAZAn_1*AsU#e zj0_-Ye%Oh*po9-`48)^6`Og!Cc3repXnz6umvsYO@C~WVCRv|^3Naxoj5-HyQB^^s)w3C7koXD+(-~!4Ckf3qH)Wjn zpY3MTnV;`A`~_$H#pr8DLG$-*b%ll)YIbukW+8c$BLKVC<(2xe3gd1*x(kx9LNiRu z71?%7J5IYYGVd39Z_~*9%%@+)nxGvdR!p44ssfk*EUaZl|2tRQG{FW9m7A;e zJTuNE(M`9hDlE<=w&MO7nXeu35a|jE^8$8Ob{xi^BxL$WMEdadHX5y3OD`ItxS8yD z7d+1&52ucl_SqRZ{s5T8Y)G~{X<$R$kQb( z(J)5{_Fkv<3k^0<;vsy?u3!~o@=H2{WlEpjAaGyZ|HcDlS~bcxJ*X?Oh=Z!}wLGu_ z4TsI=95M!UCef-nbgF+k4g35MdsCQFZ?2Wx(h$k<2Is{0rN%a}u2eB01qQ2Z@i9x- zP|Hw_d4FCQ%2viVWo=_rCXZsjS4$W0JA?NpR{YatS0VJX93hian{Nj3bDyy_50y%6 z>`F1jOin=zMD^`wE1Wn1m$RI#>UwK|bPfF^?i8L@S03(LPM4uxJMqF4T8QW`9}DPp z2vsC(mO^IKz-=WqhbiSSMdifhg)upWI^{WrbDB?VA&a0a#RNIi#E^Q0kXmj&kIndM zTVYMONF@}qge=1H{d3Q=4`CejlXFlMmTW?rS9!1an%~Jnnx)MF-Z08DAsz1 z7ZY!th9!*p601EuKUVDQd=v1`z{SJ{OkNcI!Em(h>h7whme7t18ML2tw)f6~F{6RD zodEcS`FBXW^op9&-}X_~Vs~aSdZ$c9VMqaoiN0XSQ)PGq91>g-nJE5(mUnC<&^UX5 zWK?Q6{hHrbgNxIw&%W~$unAUBfN>l=?J}CuFf_dsOJ3ZsCtq6OL5t-G>92q4(ojW$ zW?&H9Ti?A~^L_p1GUys;A48?WjptFOl1q9g>Ml}2WOo0W{`QVTP2tVwN+VPHnzs}ot?^bfrp>){rw`L z2fFz>gA<7>=7D;2*puh61pOMCelN9^+I3{-9`>&5R32K%y)+_p`I^OAe`1RgFe4TC6!W1RNSF2K}_sm2rIf3%gd!=DokN2l#;* zgcxj_kb)KqoFG01SwhKf4Ig(~9yg0@_nmcn6IAd6Oc=OJ%bt@uxbIIMy2NOvd;0SG zsUhpLaWNAEPf|xO>y-~9ksR6bX$2ZTeQjLBaW~)v<990F6N@F71pC@W7oDqmswV7XaBwc@L#M3q1!rL?;=lWhZC;YGnUgF{(5BYtcK2mdGf>- zqjFrE^7Ray;q_j}P|y@kQ;T4dk@+iPavmqx4OR~>-kYc`JPjCqga zf8>u4SZ2TF$94!|UD(lW%bV~sSTA-TBF^M7o%O5#vgy5k&C5dA|ELwO9X>6x_Tg89 zbAkVbA`Q^3jMg`!%XPb6JN%8&l4*irwfvRe!D>@10{qYFWJYXUg{HuKk`@eJ49E{H z)it59xca0tr<|lt>!|~}*3Nn)^i(Ylpe5#<+lwuu-^b$3l7Puog z**WS$i|Giw0Z_NZoK6ZH+8$oKgCbB=G5VPCsA%WFQAb#b(s3lPm?thTZ)!3Bpt=9f zeppAhy1~cTB4&gbT%P_XAA`Kx($|YpmW>M%xvxYpTBIXrO#6iJRKD(Hp5zv`lCp6X zAJ-oudQOjT@}vmDqH_AoH>+?_>qPsELAYXWCF3_=?i~hF+${USr%u^v48lvILRr1B zUex?`jVV>%#T5hBTF#8FXtP(A_L!uiB6E4GRG5~YpmEr!bH>x)40||JiW;`rXJP{=Okbzn>~GkL9mg_a`?d({yQ_THvlM zdp)$bPuouOhlGL1IR549^eYv63iCTjU5lv6DQT1tK)8hXs>SM1!h$tWVMLa9<_eRA zz40>_)_0J;nHtRR?#zO`yE~=M&dL>wSSTs~6YyUyKzvKxbjKH*JEnX9!5kidVzp0c z#%nj4gySOqB=-~D(9x?WTipZ>;pdR1zVdi(cgO4DZQvX>4=`HBPOYexR=jii3A_mU z!)f`m5PmYie}BQRc!ruvl4G)B_v6C3%?jlIox1^Fwge1Op#1=FlJ+**UdQ-ohKR`4 zi))}L46CK6Pm?_Z&k-GB<8MhZL&GF9OgOOFKEn#9m?+f3s4)Apmu1xoZO&Nztd(tm z2V@5Ckg2RsSn%R({gN0~9dQ)Xj?gf(vH;gU2rT2hT6StikTU2B1u%sY(Y>BOg@P7TXx(NgnQeky?L4!lkkU~NrnW0R2TuX5HKzr46;Bc30B6u^ zG@Kuw{&$o_UI#6YjuCEcd@mo+&_vQ@dj0g+Z@iQTg7*)?!yKrzXMB~4ep(|BPpj={ zdc%3`2PIO$UV#tWRi8i8Y@l1P;njN|nMQ_hzFb-H=~M^kbS1`TAL}?+F)eK52oq%k zQp>^~F33lm>vl9HhjHcozX)U%hkpPuJqZ@F~jc)gTMX5Hx9D4{|#`&(g`~(YDb&Z$4?oy4$M2} z9P$2vn)Rr$hGJ18#L1PsdZ7?W2u5vtrU$=YDUlNqBsTrs(}75Igxb1MSJNHPm(?}J zT7W2P`3n~x>?)!DS>yawY8rt^46``z&acG2SWs#}&4wIpMuDJ;rAXnA&_IaD{)z(} zm&EeOFBYwk`)l^m8#7E3Yq1qrPxxgcc z1%B_z6tc?wJ7*ZUgUDeV@jBb=jO;Sap}j3heJZ#Tq== zGF0MMXWmml&enbaOL*4oEHr%@CxaS9A5lR@2Z*%lte&zXmz85##8QHTuq)^a`hm1n zTqMAku9P4|IhmVUbAWSNG@o2_`~2<>(g{N68+6gMZ$NvpO6on4Qu?QC@o$6e=Qk%l9PAm9KBnhd^Rjpk|ufjJlxbN;C% z_DGM>m7fHjtI0qFyZz352ZHmcg7eKlK4T#^I-g5w2(ohx`E!yF6Lvt@tL`Q1emwox zu95bLJ$k6X0xPTtQA}Wxsn&Y(i<6b3-a!z7nivGu*^KJ4e;_&VXdH@Q`o#=AmxcfV zh!fjkyW>ljsgSOzbs)M;>=m4Lt_rMP0P5+MOa>&0u*E5{w&Xn547RIjClE;%LEWXQ zjoPipUDZ3+9}AnjJ*${q*u8`}nUIhOLqnaj5f)LGQ;y?x==^)>2gXhXD_J1E%1U`ArQC0R&Y*@^h0GQJvk*VQ& zbv=0L`xr7|so-r^PnlnxJj4YOABzj2R2I5e5b#aPv+#so+1TN@9l95h= z+gGIzE-_Mg7On)jpOD%d%Fb`YO*YPD^_#8PctOAmMA`zpQ=$SI0w!7?`|-``LDN4& z{3i~>1PrJNVG*KCLF7;{p4vZxX%^Wg+iMB|Crl3~fc1GQ<)aUMnf$-a7clbL^PEff zqf2c59lSYg6HUi^k1{z}6IJ8aUL9;rkJP7;LZa%GcJ2ITD`HSzFO^_YCFc8%9!Fp0 zJRqVLNAVMepjAL^SObI0o?St8Yov(gv?m%?r9(SXSDDQ-%)Rlbj%n{PF{On7SqUj< zwR*eUMfz#gy1-w8(qCQ~BLsNVXg311UgLl1Qqg!I(f#=eZP)ue!6e&fUc~fo(;F2;a0@zBq@EPPYl?@?%yk_ex z6B)qmeyglfcYr&RI1Q5B`JF_72G0_2fF6ZcAJrXL>6pD{$_5EI86wchjuGz4YIE@u z6C18x)5vg$VueE~bI9+96q|3vVg(eUdRb%vmqxBvgl z3tDZfy}t31X`bZ&WnK^*CR{}F3X6(BBJFCFGVy?okBj4!I0xXjK4s!jV1uYhu71NA z_4Dt7FkX{yP=ajIhoOg0 zk2fo>w-FFHYC$x>sX_cnyqcV)RMEq5z!(V9rKKIIu^Kf9Xo0}e=kV2>J2?^Vr;m9D zva5Goey7s%bc7$5EkPGF|E9pxWRR_^k(Mo70+IL#RWj=AI3)~Lf_ ze8UXoN1XU_Y%Q0S1CxC4E-tVe`cy7NmPkxf6@T?<(aMMBb>2JM6x)x*$AJS=^y?{( zzxShl9~KGqeU&|?g-X!*fO#m(B>qX`usc0N#D`c1mnxE=uOAF7f?oMsnlZ0TxGuUb zM#fYz5{Amd%?*F6-M?=un$@o%;W?p3}GwG^RxD*(UQ2ctbUe$47?$|A_>iHzv^Y8OGY>P;NXcHU>}(t za732G&jbXxM6bMrORO#o190#oBimazg~jQBbj*#9f&Fe_)&o2><#> z14}ht~{@{g`go_htNDy)DX_>)Ho}&Z2Qg1?cQj(~e)`JE4 zo<8!sKb)16yLs<4sYZ1%&gxhM3EwXEQ^q1p*0GT1TOAgJTOCG!rT^@}$x2d+DCX%I zk;qEzs~*!g5ou7RPy)n(iwDU8|2t+UT%w&g$CH88>^U|8Yi!)#=}MeHs@s(l(HcDb zG+)}v%vqSe$?TY`y5!uiP8NkKkp^ z$rxD(k&(g>0*thhRX{fB0Jj}dzj@yXL~=a|v#D&H0~CYCm`~$-6$_+&td)$qB9H3T zlZpt2UEo>DyAk!BTP9qi`5nfSo86nIztuADTcC6lC)Jy}kXqB*Qio`#`-jIqMa7GG zdJBF|eGWLAOV}GG{;9mz9!A~VFuLa|1IjpV)<=|a{H%|8`V9lSZ>yef#ZDDeOKZ7K z(vr~?Y>@P|j>YF6sjQ8k7?=7{6<4Brp&pAX=V?#`oaXfl)bjDu(-R+)tCZ_>Jt}wn zR`tOpKNb^HUjj_>z_#i!(Hmy~(|RMd`+fWOIg^dD5dccq#jWE} z^CWWswCE`QB={_zNd8SlXR(jK5s~3TcmNS?yK>$rRnG|@0=Hy)Z^k|S+OyIO`)1tQ zm+J@L3B_XQ4EgxGpa{JCzOcrR{QMj>yH}(Pp01Ie(}DYPmsw}bo<7t`l@>K^cLD=q>DqU zP1Tp6fI-gs{hj%PwKc_i>ty)^mh&#r)yb4~jRYK&DdK^x-r3mA)99}{`MtBfb30#n zndts>j+WlQDC{^*v#3uf43(Y>?OjuXI=b(2iF) zJ3z6<9grSh2RW(F;y1mUeq*#D{$z*?jk;3p%0{*m3`(N|eXH0-Q zlB>!fXM`ZG1|*IEB;>wXnf#Nj*?&bCBJckl;s1*8f6dSEX#a{Z1RZmQ4*yq#f2UY~ zwJ!f!;lHaUNPqd)3jYuK9p+yv{NFpL|2oqDy?%#+{@0O)l&t+#yQ7iH{Qv1l*PLF* Yd#CA=$?>ZA8t_j{Na|6RfX<8m0~9XE1ONa4 literal 0 HcmV?d00001 diff --git a/test-network-k8s/kube/application-deployment.yaml b/test-network-k8s/kube/application-deployment.yaml new file mode 100644 index 00000000..4e02f706 --- /dev/null +++ b/test-network-k8s/kube/application-deployment.yaml @@ -0,0 +1,48 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: application-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: application-deployment + template: + metadata: + labels: + app: application-deployment + spec: + containers: + - name: main + image: + imagePullPolicy: Always + envFrom: + - configMapRef: + name: app-fabric-org1-v1-map + resources: + requests: + memory: "50Mi" + cpu: "0.1" + volumeMounts: + - name: fabricids + mountPath: /fabric/application/wallet + - name: fabric-ccp + mountPath: /fabric/application/gateways + - name: tlscerts + mountPath: /fabric/tlscacerts + volumes: + - name: fabric-ccp + configMap: + name: app-fabric-ccp-v1-map + - name: fabricids + configMap: + name: app-fabric-ids-v1-map + - name: tlscerts + configMap: + name: app-fabric-tls-v1-map diff --git a/test-network-k8s/kube/fabric-rest-sample.yaml b/test-network-k8s/kube/fabric-rest-sample.yaml new file mode 100644 index 00000000..2bf99d7f --- /dev/null +++ b/test-network-k8s/kube/fabric-rest-sample.yaml @@ -0,0 +1,258 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: fabric-rest-sample-config-example +data: + HLF_CONNECTION_PROFILE_ORG1: | + { + "name": "test-network-org1", + "version": "1.0.0", + "client": { + "organization": "Org1", + "connection": { + "timeout": { + "peer": { + "endorser": "500" + } + } + } + }, + "organizations": { + "Org1": { + "mspid": "Org1MSP", + "peers": [ + "org1-peer1" + ], + "certificateAuthorities": [ + "org1-ecert" + ] + } + }, + "peers": { + "org1-peer1": { + "url": "grpcs://org1-peer1:7051", + "tlsCACerts": { + "pem": "-----BEGIN CERTIFICATE-----\\nMIICvzCCAmWgAwIBAgIULJGws7jbEY6ruSgDuvi9L7VphvIwCgYIKoZIzj0EAwIw\\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\\nY2Etc2VydmVyMB4XDTIxMDkyMDE2MDkwMFoXDTIyMDkyMDE2MTQwMFowYDELMAkG\\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\\ncmxlZGdlcjENMAsGA1UECxMEcGVlcjETMBEGA1UEAxMKb3JnMS1wZWVyMTBZMBMG\\nByqGSM49AgEGCCqGSM49AwEHA0IABL9e3GZBf1MeoObGxwSHkcgDEjMo+/13Qc4u\\nfSG2MKrveHBIEA4MRkHNqd+sTjoz0/1B15y2n+RiPo8uJvlyC/CjgfQwgfEwDgYD\\nVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV\\nHRMBAf8EAjAAMB0GA1UdDgQWBBSeytspiXlEzMAsnF9/wxqc9fydETAfBgNVHSME\\nGDAWgBQwru1VH0OwH3dxfPdD8w74ZIlLRzAVBgNVHREEDjAMggpvcmcxLXBlZXIx\\nMFsGCCoDBAUGBwgBBE97ImF0dHJzIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYu\\nRW5yb2xsbWVudElEIjoib3JnMS1wZWVyMSIsImhmLlR5cGUiOiJwZWVyIn19MAoG\\nCCqGSM49BAMCA0gAMEUCIQDJEjPxceCfXU5B/emrHE4JbEzrZKxLVViBWCNMsHiR\\nFgIgY+8jsvr3rlBPkpRhl8CtT2DgaP7iWvovtMYsPKhLAqk=\\n-----END CERTIFICATE-----\\n" + }, + "grpcOptions": { + "grpc-wait-for-ready-timeout": 100000, + "ssl-target-name-override": "org1-peer1", + "hostnameOverride": "org1-peer1" + } + } + }, + "certificateAuthorities": { + "org1-ecert-ca": { + "url": "https://org1-ecert-ca", + "caName": "org1-ecert-ca", + "tlsCACerts": { + "pem": "TODO" + }, + "httpOptions": { + "verify": "false" + } + } + } + } + HLF_CERTIFICATE_ORG1: | + -----BEGIN CERTIFICATE----- + MIIC2DCCAn6gAwIBAgIUTfcXDyxCS+2EQnznfjERUo4Vri8wCgYIKoZIzj0EAwIw + aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK + EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt + Y2Etc2VydmVyMB4XDTIxMDkyMDExNDEwMFoXDTIyMDkyMDExNDYwMFowYTELMAkG + A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl + cmxlZGdlcjEOMAwGA1UECxMFYWRtaW4xEzARBgNVBAMTCm9yZzEtYWRtaW4wWTAT + BgcqhkjOPQIBBggqhkjOPQMBBwNCAAT8zvJEg3FgJ5iUA5GO+n/j48bL83STpz7N + TqejWIZNVTraxE4fjT6traKiswme7gT2NY9Jl0Dj4tbif9l2I9+Oo4IBCzCCAQcw + DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFO1zWPynvyER + n9ml6XV5VvC9tIjTMB8GA1UdIwQYMBaAFPbIrI+lh8KayoRpW1YStWMhzJZSMCcG + A1UdEQQgMB6CHG9yZzEtdGxzLWNhLTg1NjdiOTg5OWYtdzU3amYwfgYIKgMEBQYH + CAEEcnsiYXR0cnMiOnsiYWJhYy5pbml0IjoidHJ1ZSIsImFkbWluIjoidHJ1ZSIs + ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JnMS1hZG1p + biIsImhmLlR5cGUiOiJhZG1pbiJ9fTAKBggqhkjOPQQDAgNIADBFAiEAv99I2J9t + WtOmIzpYix8OFl4Z+ZGRHtay83ux//sZP+MCID02hFqnNpOL/ggGFaDVpVQ/eu0t + KTfVxZEMyZnJtAhp + -----END CERTIFICATE----- + HLF_PRIVATE_KEY_ORG1: | + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg7Lb+jwZqhxT3x0lT + FpU0QSmioptgfv8TI2RP5Mjp9UKhRANCAAT8zvJEg3FgJ5iUA5GO+n/j48bL83ST + pz7NTqejWIZNVTraxE4fjT6traKiswme7gT2NY9Jl0Dj4tbif9l2I9+O + -----END PRIVATE KEY----- + HLF_CONNECTION_PROFILE_ORG2: | + { + "name": "test-network-org2", + "version": "1.0.0", + "client": { + "organization": "Org2", + "connection": { + "timeout": { + "peer": { + "endorser": "300" + } + } + } + }, + "organizations": { + "Org2": { + "mspid": "Org2MSP", + "peers": [ + "org2-peer1" + ], + "certificateAuthorities": [ + "org2-ecert-ca" + ] + } + }, + "peers": { + "org2-peer1": { + "url": "grpcs://org2-peer1:7051", + "tlsCACerts": { + "pem": "-----BEGIN CERTIFICATE-----\\nMIICKDCCAc6gAwIBAgIUJJ4wGOSCfw8XOOIx29o67wBpFB4wCgYIKoZIzj0EAwIw\\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\\nY2Etc2VydmVyMB4XDTIxMDkyMDExNDEwMFoXDTM2MDkxNjExNDEwMFowaDELMAkG\\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyzGJLZX6pe59QAIBacjfzU4I\\nHezBYLyEu4ySpFx4xwxNLE4BWqLhB1VaOuenSQATM8pmSAy7i1830oM9elKWK6NW\\nMFQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\\nFEoAAhmjq/3M8CFPc7N8SL53erL5MA8GA1UdEQQIMAaHBH8AAAEwCgYIKoZIzj0E\\nAwIDSAAwRQIhAJQ5PJOT4Gg8oiBU2KthMPkZqOLeu3Li4S3yBpLFgbsgAiB960P2\\nXPMu3HLoNXrktYOL9JzWlGyYRSPAnkap5Bsj0w==\\n-----END CERTIFICATE-----\\n" + }, + "grpcOptions": { + "ssl-target-name-override": "org2-peer1", + "hostnameOverride": "org2-peer1" + } + } + }, + "certificateAuthorities": { + "org2-ecert-ca": { + "url": "https://org2-ecert-ca", + "caName": "org2-ecert-ca", + "tlsCACerts": { + "pem": ["-----BEGIN CERTIFICATE-----\\nMIICKDCCAc6gAwIBAgIUJAF4fQK1KsnvdaUjau462D/5HPYwCgYIKoZIzj0EAwIw\\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\\nY2Etc2VydmVyMB4XDTIxMDkxOTExMTcwMFoXDTM2MDkxNTExMTcwMFowaDELMAkG\\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8bLvzagP3YANMGHVomZoGCQD\\nRgM3SenagZQ4IWqNQJSV3yTxzdgAWnPhwc+B/HdAOvAq2Oz54FmiSL9dAJoivqNW\\nMFQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\\nFDdBAwT47jtbj48aXdMfRvMPbD5tMA8GA1UdEQQIMAaHBH8AAAEwCgYIKoZIzj0E\\nAwIDSAAwRQIhAITSk4lYWqu12jZkR94aNoKT36ctaeKHuRvXs7m2qaHSAiAtUPO7\\nXlHtI9SDTRvI4DNSb2O7y7+B3WxVeCx50fivDw==\\n-----END CERTIFICATE-----\\n"] + }, + "httpOptions": { + "verify": "false" + } + } + } + } + HLF_CERTIFICATE_ORG2: | + -----BEGIN CERTIFICATE----- + MIIC2DCCAn6gAwIBAgIUY/B19uAV6H5zK4bgqF/BcYC79eEwCgYIKoZIzj0EAwIw + aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK + EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt + Y2Etc2VydmVyMB4XDTIxMDkyMDExNDEwMFoXDTIyMDkyMDExNDYwMFowYTELMAkG + A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl + cmxlZGdlcjEOMAwGA1UECxMFYWRtaW4xEzARBgNVBAMTCm9yZzItYWRtaW4wWTAT + BgcqhkjOPQIBBggqhkjOPQMBBwNCAARKTC+25gFIgbLQgSQSec3DaUJOZS6aHBAi + 0bmArVbMOxLUBT/W42ycXzfFJ9c0UAEZecDu8jxgBfEGWcbeWWMXo4IBCzCCAQcw + DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFGIXcrVhcyJ9 + WTH2zgc9/RdE1hJsMB8GA1UdIwQYMBaAFFS96ExY5RWOcsODBAfXZe+FQIq0MCcG + A1UdEQQgMB6CHG9yZzItdGxzLWNhLTY5Yzg1Zjg5YmMtNzIyZ2cwfgYIKgMEBQYH + CAEEcnsiYXR0cnMiOnsiYWJhYy5pbml0IjoidHJ1ZSIsImFkbWluIjoidHJ1ZSIs + ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JnMi1hZG1p + biIsImhmLlR5cGUiOiJhZG1pbiJ9fTAKBggqhkjOPQQDAgNIADBFAiEAhrXwM7Ng + IGxgF8irY7NbkQp1xqphy3tv6JbK6HPF+O8CIELMkzOclVK2rRC1K5PF99G7Cmmm + KsVw31cJcV4NTDI7 + -----END CERTIFICATE----- + HLF_PRIVATE_KEY_ORG2: | + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPJgLniT9EqcaUNbi + F3EqGyBP9LDg1baXR/5dV6xedt+hRANCAARKTC+25gFIgbLQgSQSec3DaUJOZS6a + HBAi0bmArVbMOxLUBT/W42ycXzfFJ9c0UAEZecDu8jxgBfEGWcbeWWMX + -----END PRIVATE KEY----- + + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fabric-rest-sample +spec: + replicas: 1 + selector: + matchLabels: + app: fabric-rest-sample + template: + metadata: + labels: + app: fabric-rest-sample + spec: + containers: + - name: main + image: ghcr.io/hyperledgendary/fabric-rest-sample + imagePullPolicy: IfNotPresent + env: + - name: LOG_LEVEL + value: debug + - name: HFC_LOGGING + value: '{ "debug": "console" }' + - name: PORT + value: "3000" + - name: RETRY_DELAY + value: "3000" + - name: MAX_RETRY_COUNT + value: "5" + - name: HLF_COMMIT_TIMEOUT + value: "3000" + - name: HLF_ENDORSE_TIMEOUT + value: "30" + - name: REDIS_HOST + value: "localhost" + - name: REDIS_PORT + value: "6379" + - name: ORG1_APIKEY + value: "97834158-3224-4CE7-95F9-A148C886653E" + - name: ORG2_APIKEY + value: "BC42E734-062D-4AEE-A591-5973CB763430" + - name: AS_LOCAL_HOST + value: "false" + - name: HLF_CHAINCODE_NAME + value: "asset-transfer-basic" +# - name: REDIS_USERNAME +# value: redisuser +# - name: REDIS_PASSWORD +# value: redispasword + + envFrom: + - configMapRef: + name: fabric-rest-sample-config + ports: + - containerPort: 3000 + - name: redis + image: redis:6.2.5 + ports: + - containerPort: 6379 + +--- +apiVersion: v1 +kind: Service +metadata: + name: fabric-rest-sample +spec: + ports: + - name: http + port: 3000 + protocol: TCP + selector: + app: fabric-rest-sample + + +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: fabric-rest-sample +# annotations: +# nginx.ingress.kubernetes.io/rewrite-target: /$1 +spec: + rules: + - http: + paths: +# - path: "/fabric-rest-sample/(.*)" + - path: "/" + pathType: Prefix + backend: + service: + name: fabric-rest-sample + port: + number: 3000 diff --git a/test-network-k8s/kube/ingress-nginx.yaml b/test-network-k8s/kube/ingress-nginx.yaml new file mode 100644 index 00000000..90f5de31 --- /dev/null +++ b/test-network-k8s/kube/ingress-nginx.yaml @@ -0,0 +1,687 @@ + +apiVersion: v1 +kind: Namespace +metadata: + name: ingress-nginx + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + +--- +# Source: ingress-nginx/templates/controller-serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: controller + name: ingress-nginx + namespace: ingress-nginx +automountServiceAccountToken: true +--- +# Source: ingress-nginx/templates/controller-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: controller + name: ingress-nginx-controller + namespace: ingress-nginx +data: +--- +# Source: ingress-nginx/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + name: ingress-nginx +rules: + - apiGroups: + - '' + resources: + - configmaps + - endpoints + - nodes + - pods + - secrets + verbs: + - list + - watch + - apiGroups: + - '' + resources: + - nodes + verbs: + - get + - apiGroups: + - '' + resources: + - services + verbs: + - get + - list + - watch + - apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - watch + - apiGroups: + - '' + resources: + - events + verbs: + - create + - patch + - apiGroups: + - networking.k8s.io + resources: + - ingresses/status + verbs: + - update + - apiGroups: + - networking.k8s.io + resources: + - ingressclasses + verbs: + - get + - list + - watch +--- +# Source: ingress-nginx/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + name: ingress-nginx +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ingress-nginx +subjects: + - kind: ServiceAccount + name: ingress-nginx + namespace: ingress-nginx +--- +# Source: ingress-nginx/templates/controller-role.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: controller + name: ingress-nginx + namespace: ingress-nginx +rules: + - apiGroups: + - '' + resources: + - namespaces + verbs: + - get + - apiGroups: + - '' + resources: + - configmaps + - pods + - secrets + - endpoints + verbs: + - get + - list + - watch + - apiGroups: + - '' + resources: + - services + verbs: + - get + - list + - watch + - apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - watch + - apiGroups: + - networking.k8s.io + resources: + - ingresses/status + verbs: + - update + - apiGroups: + - networking.k8s.io + resources: + - ingressclasses + verbs: + - get + - list + - watch + - apiGroups: + - '' + resources: + - configmaps + resourceNames: + - ingress-controller-leader + verbs: + - get + - update + - apiGroups: + - '' + resources: + - configmaps + verbs: + - create + - apiGroups: + - '' + resources: + - events + verbs: + - create + - patch +--- +# Source: ingress-nginx/templates/controller-rolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: controller + name: ingress-nginx + namespace: ingress-nginx +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ingress-nginx +subjects: + - kind: ServiceAccount + name: ingress-nginx + namespace: ingress-nginx +--- +# Source: ingress-nginx/templates/controller-service-webhook.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: controller + name: ingress-nginx-controller-admission + namespace: ingress-nginx +spec: + type: ClusterIP + ports: + - name: https-webhook + port: 443 + targetPort: webhook + appProtocol: https + selector: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/component: controller +--- +# Source: ingress-nginx/templates/controller-service.yaml +apiVersion: v1 +kind: Service +metadata: + annotations: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: controller + name: ingress-nginx-controller + namespace: ingress-nginx +spec: + type: NodePort + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http + appProtocol: http + - name: https + port: 443 + protocol: TCP + targetPort: https + appProtocol: https + selector: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/component: controller +--- +# Source: ingress-nginx/templates/controller-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: controller + name: ingress-nginx-controller + namespace: ingress-nginx +spec: + selector: + matchLabels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/component: controller + revisionHistoryLimit: 10 + strategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate + minReadySeconds: 0 + template: + metadata: + labels: + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/component: controller + spec: + dnsPolicy: ClusterFirst + containers: + - name: controller + image: k8s.gcr.io/ingress-nginx/controller:v1.0.1@sha256:26bbd57f32bac3b30f90373005ef669aae324a4de4c19588a13ddba399c6664e + imagePullPolicy: IfNotPresent + lifecycle: + preStop: + exec: + command: + - /wait-shutdown + args: + - /nginx-ingress-controller + - --election-id=ingress-controller-leader + - --controller-class=k8s.io/ingress-nginx + - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller + - --validating-webhook=:8443 + - --validating-webhook-certificate=/usr/local/certificates/cert + - --validating-webhook-key=/usr/local/certificates/key + - --publish-status-address=localhost + - --watch-ingress-without-class + - --enable-ssl-passthrough + securityContext: + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + runAsUser: 101 + allowPrivilegeEscalation: true + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: LD_PRELOAD + value: /usr/local/lib/libmimalloc.so + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10254 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + ports: + - name: http + containerPort: 80 + protocol: TCP + hostPort: 80 + - name: https + containerPort: 443 + protocol: TCP + hostPort: 443 + - name: webhook + containerPort: 8443 + protocol: TCP + volumeMounts: + - name: webhook-cert + mountPath: /usr/local/certificates/ + readOnly: true + resources: + requests: + cpu: 100m + memory: 90Mi + nodeSelector: + ingress-ready: 'true' + kubernetes.io/os: linux + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Equal + serviceAccountName: ingress-nginx + terminationGracePeriodSeconds: 0 + volumes: + - name: webhook-cert + secret: + secretName: ingress-nginx-admission +--- +# Source: ingress-nginx/templates/controller-ingressclass.yaml +# We don't support namespaced ingressClass yet +# So a ClusterRole and a ClusterRoleBinding is required +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: controller + name: nginx + namespace: ingress-nginx +spec: + controller: k8s.io/ingress-nginx +--- +# Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml +# before changing this value, check the required kubernetes version +# https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook + name: ingress-nginx-admission +webhooks: + - name: validate.nginx.ingress.kubernetes.io + matchPolicy: Equivalent + rules: + - apiGroups: + - networking.k8s.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - ingresses + failurePolicy: Fail + sideEffects: None + admissionReviewVersions: + - v1 + clientConfig: + service: + namespace: ingress-nginx + name: ingress-nginx-controller-admission + path: /networking/v1/ingresses +--- +# Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ingress-nginx-admission + namespace: ingress-nginx + annotations: + helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook +--- +# Source: ingress-nginx/templates/admission-webhooks/job-patch/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: ingress-nginx-admission + annotations: + helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook +rules: + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + verbs: + - get + - update +--- +# Source: ingress-nginx/templates/admission-webhooks/job-patch/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ingress-nginx-admission + annotations: + helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ingress-nginx-admission +subjects: + - kind: ServiceAccount + name: ingress-nginx-admission + namespace: ingress-nginx +--- +# Source: ingress-nginx/templates/admission-webhooks/job-patch/role.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: ingress-nginx-admission + namespace: ingress-nginx + annotations: + helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook +rules: + - apiGroups: + - '' + resources: + - secrets + verbs: + - get + - create +--- +# Source: ingress-nginx/templates/admission-webhooks/job-patch/rolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: ingress-nginx-admission + namespace: ingress-nginx + annotations: + helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: ingress-nginx-admission +subjects: + - kind: ServiceAccount + name: ingress-nginx-admission + namespace: ingress-nginx +--- +# Source: ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: ingress-nginx-admission-create + namespace: ingress-nginx + annotations: + helm.sh/hook: pre-install,pre-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook +spec: + template: + metadata: + name: ingress-nginx-admission-create + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook + spec: + containers: + - name: create + image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068 + imagePullPolicy: IfNotPresent + args: + - create + - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc + - --namespace=$(POD_NAMESPACE) + - --secret-name=ingress-nginx-admission + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + restartPolicy: OnFailure + serviceAccountName: ingress-nginx-admission + nodeSelector: + kubernetes.io/os: linux + securityContext: + runAsNonRoot: true + runAsUser: 2000 +--- +# Source: ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: ingress-nginx-admission-patch + namespace: ingress-nginx + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook +spec: + template: + metadata: + name: ingress-nginx-admission-patch + labels: + helm.sh/chart: ingress-nginx-4.0.2 + app.kubernetes.io/name: ingress-nginx + app.kubernetes.io/instance: ingress-nginx + app.kubernetes.io/version: 1.0.1 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/component: admission-webhook + spec: + containers: + - name: patch + image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068 + imagePullPolicy: IfNotPresent + args: + - patch + - --webhook-name=ingress-nginx-admission + - --namespace=$(POD_NAMESPACE) + - --patch-mutating=false + - --secret-name=ingress-nginx-admission + - --patch-failure-policy=Fail + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + restartPolicy: OnFailure + serviceAccountName: ingress-nginx-admission + nodeSelector: + kubernetes.io/os: linux + securityContext: + runAsNonRoot: true + runAsUser: 2000 diff --git a/test-network-k8s/kube/job-scrub-fabric-volumes.yaml b/test-network-k8s/kube/job-scrub-fabric-volumes.yaml new file mode 100644 index 00000000..2acddc92 --- /dev/null +++ b/test-network-k8s/kube/job-scrub-fabric-volumes.yaml @@ -0,0 +1,43 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: job-scrub-fabric-volumes +spec: + backoffLimit: 0 + completions: 1 + template: + metadata: + name: job-scrub-fabric-volumes + spec: + restartPolicy: "Never" + containers: + - name: main + image: busybox + command: + - sh + - -c + - "rm -rvf /mnt/fabric-*/*" + volumeMounts: + - name: fabric-org0-volume + mountPath: /mnt/fabric-org0 + - name: fabric-org1-volume + mountPath: /mnt/fabric-org1 + - name: fabric-org2-volume + mountPath: /mnt/fabric-org2 + volumes: + - name: fabric-org0-volume + persistentVolumeClaim: + claimName: fabric-org0 + - name: fabric-org1-volume + persistentVolumeClaim: + claimName: fabric-org1 + - name: fabric-org2-volume + persistentVolumeClaim: + claimName: fabric-org2 + diff --git a/test-network-k8s/kube/ns-test-network.yaml b/test-network-k8s/kube/ns-test-network.yaml new file mode 100644 index 00000000..f9ef39e0 --- /dev/null +++ b/test-network-k8s/kube/ns-test-network.yaml @@ -0,0 +1,10 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: Namespace +metadata: + name: test-network diff --git a/test-network-k8s/kube/org0/org0-admin-cli.yaml b/test-network-k8s/kube/org0/org0-admin-cli.yaml new file mode 100644 index 00000000..c7bf84bb --- /dev/null +++ b/test-network-k8s/kube/org0/org0-admin-cli.yaml @@ -0,0 +1,61 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org0-admin-cli +spec: + replicas: 1 + selector: + matchLabels: + app: org0-admin-cli + template: + metadata: + labels: + app: org0-admin-cli + spec: + containers: + - name: main + image: hyperledger/fabric-tools:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + env: + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric/config + args: + - sleep + - "2147483647" + workingDir: /root + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + + # This init container will unfurl all of the MSP archives listed in the msp-config config map. + initContainers: + - name: msp-unfurl + image: busybox + command: + - sh + - -c + - "for msp in $(ls /msp/msp-*.tgz); do echo $msp && tar zxvf $msp -C /var/hyperledger/fabric; done" + volumeMounts: + - name: msp-config + mountPath: /msp + - name: fabric-volume + mountPath: /var/hyperledger + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org0 + - name: fabric-config + configMap: + name: org0-config + - name: msp-config + configMap: + name: msp-config diff --git a/test-network-k8s/kube/org0/org0-ecert-ca.yaml b/test-network-k8s/kube/org0/org0-ecert-ca.yaml new file mode 100644 index 00000000..40c2edeb --- /dev/null +++ b/test-network-k8s/kube/org0/org0-ecert-ca.yaml @@ -0,0 +1,69 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org0-ecert-ca +spec: + replicas: 1 + selector: + matchLabels: + app: org0-ecert-ca + template: + metadata: + labels: + app: org0-ecert-ca + spec: + containers: + - name: main + image: hyperledger/fabric-ca:1.5.2 + env: + - name: FABRIC_CA_SERVER_CA_NAME + value: "org0-ecert-ca" + - name: FABRIC_CA_SERVER_DEBUG + value: "false" + - name: FABRIC_CA_SERVER_HOME + value: "/var/hyperledger/fabric-ca-server" + - name: FABRIC_CA_SERVER_TLS_CERTFILE + value: "/var/hyperledger/fabric-ca-client/tls-ca/rcaadmin/msp/signcerts/cert.pem" + - name: FABRIC_CA_SERVER_TLS_KEYFILE + value: "/var/hyperledger/fabric-ca-client/tls-ca/rcaadmin/msp/keystore/key.pem" + - name: FABRIC_CA_CLIENT_HOME + value: "/var/hyperledger/fabric-ca-client" + ports: + - containerPort: 443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric-ca-server/fabric-ca-server-config.yaml + subPath: fabric-ecert-ca-server-config.yaml + readinessProbe: + tcpSocket: + port: 443 + initialDelaySeconds: 2 + periodSeconds: 5 + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org0 + - name: fabric-config + configMap: + name: org0-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org0-ecert-ca +spec: + ports: + - name: tls + port: 443 + protocol: TCP + selector: + app: org0-ecert-ca \ No newline at end of file diff --git a/test-network-k8s/kube/org0/org0-orderer1.yaml b/test-network-k8s/kube/org0/org0-orderer1.yaml new file mode 100644 index 00000000..a37b274d --- /dev/null +++ b/test-network-k8s/kube/org0/org0-orderer1.yaml @@ -0,0 +1,85 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org0-orderer1-env +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: INFO # debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info + ORDERER_GENERAL_LISTENADDRESS: 0.0.0.0 + ORDERER_GENERAL_LISTENPORT: "6050" + ORDERER_GENERAL_LOCALMSPID: OrdererMSP + ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp + ORDERER_GENERAL_TLS_ENABLED: "true" + ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/signcerts/cert.pem + ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/cacerts/org0-tls-ca.pem + ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/keystore/server.key + ORDERER_GENERAL_BOOTSTRAPMETHOD: none + ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer1 + ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer1/etcdraft/wal + ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer1/etcdraft/wal + ORDERER_OPERATIONS_LISTENADDRESS: 0.0.0.0:8443 + ORDERER_ADMIN_LISTENADDRESS: 0.0.0.0:9443 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org0-orderer1 +spec: + replicas: 1 + selector: + matchLabels: + app: org0-orderer1 + template: + metadata: + labels: + app: org0-orderer1 + spec: + containers: + - name: main + image: hyperledger/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: org0-orderer1-env + ports: + - containerPort: 6050 + - containerPort: 8443 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org0 + - name: fabric-config + configMap: + name: org0-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org0-orderer1 +spec: + ports: + - name: general + port: 6050 + protocol: TCP + - name: operations + port: 8443 + protocol: TCP + - name: admin + port: 9443 + protocol: TCP + selector: + app: org0-orderer1 \ No newline at end of file diff --git a/test-network-k8s/kube/org0/org0-orderer2.yaml b/test-network-k8s/kube/org0/org0-orderer2.yaml new file mode 100644 index 00000000..0070fda9 --- /dev/null +++ b/test-network-k8s/kube/org0/org0-orderer2.yaml @@ -0,0 +1,85 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org0-orderer2-env +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: INFO # debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info + ORDERER_GENERAL_LISTENADDRESS: 0.0.0.0 + ORDERER_GENERAL_LISTENPORT: "6050" + ORDERER_GENERAL_LOCALMSPID: OrdererMSP + ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/msp + ORDERER_GENERAL_TLS_ENABLED: "true" + ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/signcerts/cert.pem + ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/cacerts/org0-tls-ca.pem + ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/keystore/server.key + ORDERER_GENERAL_BOOTSTRAPMETHOD: none + ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer2 + ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer2/etcdraft/wal + ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer2/etcdraft/wal + ORDERER_OPERATIONS_LISTENADDRESS: 0.0.0.0:8443 + ORDERER_ADMIN_LISTENADDRESS: 0.0.0.0:9443 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org0-orderer2 +spec: + replicas: 1 + selector: + matchLabels: + app: org0-orderer2 + template: + metadata: + labels: + app: org0-orderer2 + spec: + containers: + - name: main + image: hyperledger/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: org0-orderer2-env + ports: + - containerPort: 6050 + - containerPort: 8443 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org0 + - name: fabric-config + configMap: + name: org0-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org0-orderer2 +spec: + ports: + - name: general + port: 6050 + protocol: TCP + - name: operations + port: 8443 + protocol: TCP + - name: admin + port: 9443 + protocol: TCP + selector: + app: org0-orderer2 \ No newline at end of file diff --git a/test-network-k8s/kube/org0/org0-orderer3.yaml b/test-network-k8s/kube/org0/org0-orderer3.yaml new file mode 100644 index 00000000..4db6edbf --- /dev/null +++ b/test-network-k8s/kube/org0/org0-orderer3.yaml @@ -0,0 +1,85 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org0-orderer3-env +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: INFO # debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info + ORDERER_GENERAL_LISTENADDRESS: 0.0.0.0 + ORDERER_GENERAL_LISTENPORT: "6050" + ORDERER_GENERAL_LOCALMSPID: OrdererMSP + ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/msp + ORDERER_GENERAL_TLS_ENABLED: "true" + ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/signcerts/cert.pem + ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/cacerts/org0-tls-ca.pem + ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/keystore/server.key + ORDERER_GENERAL_BOOTSTRAPMETHOD: none + ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer3 + ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer3/etcdraft/wal + ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer3/etcdraft/wal + ORDERER_OPERATIONS_LISTENADDRESS: 0.0.0.0:8443 + ORDERER_ADMIN_LISTENADDRESS: 0.0.0.0:9443 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org0-orderer3 +spec: + replicas: 1 + selector: + matchLabels: + app: org0-orderer3 + template: + metadata: + labels: + app: org0-orderer3 + spec: + containers: + - name: main + image: hyperledger/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: org0-orderer3-env + ports: + - containerPort: 6050 + - containerPort: 8443 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org0 + - name: fabric-config + configMap: + name: org0-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org0-orderer3 +spec: + ports: + - name: general + port: 6050 + protocol: TCP + - name: operations + port: 8443 + protocol: TCP + - name: admin + port: 9443 + protocol: TCP + selector: + app: org0-orderer3 \ No newline at end of file diff --git a/test-network-k8s/kube/org0/org0-tls-ca.yaml b/test-network-k8s/kube/org0/org0-tls-ca.yaml new file mode 100644 index 00000000..179d9c44 --- /dev/null +++ b/test-network-k8s/kube/org0/org0-tls-ca.yaml @@ -0,0 +1,65 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org0-tls-ca +spec: + replicas: 1 + selector: + matchLabels: + app: org0-tls-ca + template: + metadata: + labels: + app: org0-tls-ca + spec: + containers: + - name: main + image: hyperledger/fabric-ca:1.5.2 + env: + - name: FABRIC_CA_SERVER_CA_NAME + value: "org0-tls-ca" + - name: FABRIC_CA_SERVER_DEBUG + value: "false" + - name: FABRIC_CA_SERVER_HOME + value: "/var/hyperledger/fabric-tls-ca-server" + - name: FABRIC_CA_CLIENT_HOME + value: "/var/hyperledger/fabric-ca-client" + ports: + - containerPort: 443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric-tls-ca-server/fabric-ca-server-config.yaml + subPath: fabric-tls-ca-server-config.yaml + readinessProbe: + tcpSocket: + port: 443 + initialDelaySeconds: 2 + periodSeconds: 5 + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org0 + - name: fabric-config + configMap: + name: org0-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org0-tls-ca +spec: + ports: + - name: tls + port: 443 + protocol: TCP + selector: + app: org0-tls-ca \ No newline at end of file diff --git a/test-network-k8s/kube/org1/org1-admin-cli.yaml b/test-network-k8s/kube/org1/org1-admin-cli.yaml new file mode 100644 index 00000000..665f3595 --- /dev/null +++ b/test-network-k8s/kube/org1/org1-admin-cli.yaml @@ -0,0 +1,65 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org1-admin-cli +spec: + replicas: 1 + selector: + matchLabels: + app: org1-admin-cli + template: + metadata: + labels: + app: org1-admin-cli + spec: + containers: + - name: main + image: hyperledger/fabric-tools:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + env: + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric/config + - name: CORE_PEER_MSPCONFIGPATH + value: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp + - name: CORE_PEER_TLS_ROOTCERT_FILE + value: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/msp/tlscacerts/org1-tls-ca.pem + args: + - sleep + - "2147483647" + workingDir: /root + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + + # This init container will unfurl all of the MSP archives listed in the msp-config config map. + initContainers: + - name: msp-unfurl + image: busybox + command: + - sh + - -c + - "for msp in $(ls /msp/msp-*.tgz); do echo $msp && tar zxvf $msp -C /var/hyperledger/fabric; done" + volumeMounts: + - name: msp-config + mountPath: /msp + - name: fabric-volume + mountPath: /var/hyperledger + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org1 + - name: fabric-config + configMap: + name: org1-config + - name: msp-config + configMap: + name: msp-config diff --git a/test-network-k8s/kube/org1/org1-cc-template.yaml b/test-network-k8s/kube/org1/org1-cc-template.yaml new file mode 100644 index 00000000..4c72bb4e --- /dev/null +++ b/test-network-k8s/kube/org1/org1-cc-template.yaml @@ -0,0 +1,45 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org1-cc-{{CHAINCODE_NAME}} +spec: + replicas: 1 + selector: + matchLabels: + app: org1-cc-{{CHAINCODE_NAME}} + template: + metadata: + labels: + app: org1-cc-{{CHAINCODE_NAME}} + spec: + containers: + - name: main + image: {{CHAINCODE_IMAGE}} + env: + - name: CHAINCODE_SERVER_ADDRESS + value: 0.0.0.0:9999 + + # todo: load with an envFrom and a dynamic config map with the ID. + - name: CHAINCODE_ID + value: {{CHAINCODE_ID}} + ports: + - containerPort: 9999 + +--- +apiVersion: v1 +kind: Service +metadata: + name: org1-cc-{{CHAINCODE_NAME}} +spec: + ports: + - name: chaincode + port: 9999 + protocol: TCP + selector: + app: org1-cc-{{CHAINCODE_NAME}} \ No newline at end of file diff --git a/test-network-k8s/kube/org1/org1-ecert-ca.yaml b/test-network-k8s/kube/org1/org1-ecert-ca.yaml new file mode 100644 index 00000000..e3da8d11 --- /dev/null +++ b/test-network-k8s/kube/org1/org1-ecert-ca.yaml @@ -0,0 +1,69 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org1-ecert-ca +spec: + replicas: 1 + selector: + matchLabels: + app: org1-ecert-ca + template: + metadata: + labels: + app: org1-ecert-ca + spec: + containers: + - name: main + image: hyperledger/fabric-ca:1.5.2 + env: + - name: FABRIC_CA_SERVER_CA_NAME + value: "org1-ecert-ca" + - name: FABRIC_CA_SERVER_DEBUG + value: "false" + - name: FABRIC_CA_SERVER_HOME + value: "/var/hyperledger/fabric-ca-server" + - name: FABRIC_CA_SERVER_TLS_CERTFILE + value: "/var/hyperledger/fabric-ca-client/tls-ca/rcaadmin/msp/signcerts/cert.pem" + - name: FABRIC_CA_SERVER_TLS_KEYFILE + value: "/var/hyperledger/fabric-ca-client/tls-ca/rcaadmin/msp/keystore/key.pem" + - name: FABRIC_CA_CLIENT_HOME + value: "/var/hyperledger/fabric-ca-client" + ports: + - containerPort: 443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric-ca-server/fabric-ca-server-config.yaml + subPath: fabric-ecert-ca-server-config.yaml + readinessProbe: + tcpSocket: + port: 443 + initialDelaySeconds: 2 + periodSeconds: 5 + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org1 + - name: fabric-config + configMap: + name: org1-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org1-ecert-ca +spec: + ports: + - name: tls + port: 443 + protocol: TCP + selector: + app: org1-ecert-ca \ No newline at end of file diff --git a/test-network-k8s/kube/org1/org1-peer1.yaml b/test-network-k8s/kube/org1/org1-peer1.yaml new file mode 100644 index 00000000..0f756a40 --- /dev/null +++ b/test-network-k8s/kube/org1/org1-peer1.yaml @@ -0,0 +1,103 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org1-peer1-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" + CORE_PEER_TLS_ENABLED: "true" + CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/signcerts/cert.pem + CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/keystore/server.key + CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/cacerts/org1-tls-ca.pem + CORE_PEER_ID: org1-peer1.org1.example.com + CORE_PEER_ADDRESS: org1-peer1:7051 + CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 + CORE_PEER_CHAINCODEADDRESS: org1-peer1:7052 + CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 + # bootstrap peer is the other peer in the same org + CORE_PEER_GOSSIP_BOOTSTRAP: org1-peer2:7051 + CORE_PEER_GOSSIP_EXTERNALENDPOINT: org1-peer1:7051 + CORE_PEER_LOCALMSPID: Org1MSP + CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/msp + CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 + CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org1-peer1.org1.example.com + CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org1-peer1.org1.example.com/snapshots + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org1-peer1 +spec: + replicas: 1 + selector: + matchLabels: + app: org1-peer1 + template: + metadata: + labels: + app: org1-peer1 + spec: + containers: + - name: main + image: hyperledger/fabric-peer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: org1-peer1-config + ports: + - containerPort: 7051 + - containerPort: 7052 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + - name: ccs-builder + mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin + + # load the external chaincode builder into the peer image prior to peer launch. + initContainers: + - name: fabric-ccs-builder + image: ghcr.io/hyperledgendary/fabric-ccs-builder + imagePullPolicy: IfNotPresent + command: [sh, -c] + args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] + volumeMounts: + - name: ccs-builder + mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org1 + - name: fabric-config + configMap: + name: org1-config + - name: ccs-builder + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: org1-peer1 +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + - name: chaincode + port: 7052 + protocol: TCP + - name: operations + port: 9443 + protocol: TCP + selector: + app: org1-peer1 \ No newline at end of file diff --git a/test-network-k8s/kube/org1/org1-peer2.yaml b/test-network-k8s/kube/org1/org1-peer2.yaml new file mode 100644 index 00000000..152c950e --- /dev/null +++ b/test-network-k8s/kube/org1/org1-peer2.yaml @@ -0,0 +1,89 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org1-peer2-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" + CORE_PEER_TLS_ENABLED: "true" + CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/signcerts/cert.pem + CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/keystore/server.key + CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/cacerts/org1-tls-ca.pem + CORE_PEER_ID: org1-peer2.org1.example.com + CORE_PEER_ADDRESS: org1-peer2:7051 + CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 + CORE_PEER_CHAINCODEADDRESS: org1-peer2:7052 + CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 + # bootstrap peer is the other peer in the same org + CORE_PEER_GOSSIP_BOOTSTRAP: org1-peer1:7051 + CORE_PEER_GOSSIP_EXTERNALENDPOINT: org1-peer2:7051 + CORE_PEER_LOCALMSPID: Org1MSP + CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/msp + CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 + CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org1-peer2.org1.example.com + CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org1-peer2.org1.example.com/snapshots + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org1-peer2 +spec: + replicas: 1 + selector: + matchLabels: + app: org1-peer2 + template: + metadata: + labels: + app: org1-peer2 + spec: + containers: + - name: main + image: hyperledger/fabric-peer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: org1-peer2-config + ports: + - containerPort: 7051 + - containerPort: 7052 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org1 + - name: fabric-config + configMap: + name: org1-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org1-peer2 +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + - name: chaincode + port: 7052 + protocol: TCP + - name: operations + port: 9443 + protocol: TCP + selector: + app: org1-peer2 \ No newline at end of file diff --git a/test-network-k8s/kube/org1/org1-tls-ca.yaml b/test-network-k8s/kube/org1/org1-tls-ca.yaml new file mode 100644 index 00000000..afedbe4d --- /dev/null +++ b/test-network-k8s/kube/org1/org1-tls-ca.yaml @@ -0,0 +1,65 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org1-tls-ca +spec: + replicas: 1 + selector: + matchLabels: + app: org1-tls-ca + template: + metadata: + labels: + app: org1-tls-ca + spec: + containers: + - name: main + image: hyperledger/fabric-ca:1.5.2 + env: + - name: FABRIC_CA_SERVER_CA_NAME + value: "org1-tls-ca" + - name: FABRIC_CA_SERVER_DEBUG + value: "false" + - name: FABRIC_CA_SERVER_HOME + value: "/var/hyperledger/fabric-tls-ca-server" + - name: FABRIC_CA_CLIENT_HOME + value: "/var/hyperledger/fabric-ca-client" + ports: + - containerPort: 443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric-tls-ca-server/fabric-ca-server-config.yaml + subPath: fabric-tls-ca-server-config.yaml + readinessProbe: + tcpSocket: + port: 443 + initialDelaySeconds: 2 + periodSeconds: 5 + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org1 + - name: fabric-config + configMap: + name: org1-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org1-tls-ca +spec: + ports: + - name: tls + port: 443 + protocol: TCP + selector: + app: org1-tls-ca \ No newline at end of file diff --git a/test-network-k8s/kube/org2/org2-admin-cli.yaml b/test-network-k8s/kube/org2/org2-admin-cli.yaml new file mode 100644 index 00000000..be47123a --- /dev/null +++ b/test-network-k8s/kube/org2/org2-admin-cli.yaml @@ -0,0 +1,65 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org2-admin-cli +spec: + replicas: 1 + selector: + matchLabels: + app: org2-admin-cli + template: + metadata: + labels: + app: org2-admin-cli + spec: + containers: + - name: main + image: hyperledger/fabric-tools:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + env: + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric/config + - name: CORE_PEER_MSPCONFIGPATH + value: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp + - name: CORE_PEER_TLS_ROOTCERT_FILE + value: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/msp/tlscacerts/org2-tls-ca.pem + args: + - sleep + - "2147483647" + workingDir: /root + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + + # This init container will unfurl all of the MSP archives listed in the msp-config config map. + initContainers: + - name: msp-unfurl + image: busybox + command: + - sh + - -c + - "for msp in $(ls /msp/msp-*.tgz); do echo $msp && tar zxvf $msp -C /var/hyperledger/fabric; done" + volumeMounts: + - name: msp-config + mountPath: /msp + - name: fabric-volume + mountPath: /var/hyperledger + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org2 + - name: fabric-config + configMap: + name: org2-config + - name: msp-config + configMap: + name: msp-config diff --git a/test-network-k8s/kube/org2/org2-cc.yaml b/test-network-k8s/kube/org2/org2-cc.yaml new file mode 100644 index 00000000..5075f2ba --- /dev/null +++ b/test-network-k8s/kube/org2/org2-cc.yaml @@ -0,0 +1,6 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + diff --git a/test-network-k8s/kube/org2/org2-ecert-ca.yaml b/test-network-k8s/kube/org2/org2-ecert-ca.yaml new file mode 100644 index 00000000..56c3350f --- /dev/null +++ b/test-network-k8s/kube/org2/org2-ecert-ca.yaml @@ -0,0 +1,69 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org2-ecert-ca +spec: + replicas: 1 + selector: + matchLabels: + app: org2-ecert-ca + template: + metadata: + labels: + app: org2-ecert-ca + spec: + containers: + - name: main + image: hyperledger/fabric-ca:1.5.2 + env: + - name: FABRIC_CA_SERVER_CA_NAME + value: "org2-ecert-ca" + - name: FABRIC_CA_SERVER_DEBUG + value: "false" + - name: FABRIC_CA_SERVER_HOME + value: "/var/hyperledger/fabric-ca-server" + - name: FABRIC_CA_SERVER_TLS_CERTFILE + value: "/var/hyperledger/fabric-ca-client/tls-ca/rcaadmin/msp/signcerts/cert.pem" + - name: FABRIC_CA_SERVER_TLS_KEYFILE + value: "/var/hyperledger/fabric-ca-client/tls-ca/rcaadmin/msp/keystore/key.pem" + - name: FABRIC_CA_CLIENT_HOME + value: "/var/hyperledger/fabric-ca-client" + ports: + - containerPort: 443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric-ca-server/fabric-ca-server-config.yaml + subPath: fabric-ecert-ca-server-config.yaml + readinessProbe: + tcpSocket: + port: 443 + initialDelaySeconds: 2 + periodSeconds: 5 + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org2 + - name: fabric-config + configMap: + name: org2-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org2-ecert-ca +spec: + ports: + - name: tls + port: 443 + protocol: TCP + selector: + app: org2-ecert-ca \ No newline at end of file diff --git a/test-network-k8s/kube/org2/org2-peer1.yaml b/test-network-k8s/kube/org2/org2-peer1.yaml new file mode 100644 index 00000000..193dd2cc --- /dev/null +++ b/test-network-k8s/kube/org2/org2-peer1.yaml @@ -0,0 +1,104 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org2-peer1-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" + CORE_PEER_TLS_ENABLED: "true" + CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/signcerts/cert.pem + CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/keystore/server.key + CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/cacerts/org2-tls-ca.pem + CORE_PEER_ID: org2-peer1.org2.example.com + CORE_PEER_ADDRESS: org2-peer1:7051 + CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 + CORE_PEER_CHAINCODEADDRESS: org2-peer1:7052 + CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 + # bootstrap peer is the other peer in the same org + CORE_PEER_GOSSIP_BOOTSTRAP: org2-peer2:7051 + CORE_PEER_GOSSIP_EXTERNALENDPOINT: org2-peer1:7051 + CORE_PEER_LOCALMSPID: Org2MSP + CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/msp + CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 + CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org2-peer1.org2.example.com + CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org2-peer1.org2.example.com/snapshots + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org2-peer1 +spec: + replicas: 1 + selector: + matchLabels: + app: org2-peer1 + template: + metadata: + labels: + app: org2-peer1 + spec: + containers: + - name: main + image: hyperledger/fabric-peer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: org2-peer1-config + ports: + - containerPort: 7051 + - containerPort: 7052 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + - name: ccs-builder + mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin + + # load the external chaincode builder into the peer image prior to peer launch. + initContainers: + - name: fabric-ccs-builder + image: ghcr.io/hyperledgendary/fabric-ccs-builder + imagePullPolicy: IfNotPresent + command: [sh, -c] + args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] + volumeMounts: + - name: ccs-builder + mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org2 + - name: fabric-config + configMap: + name: org2-config + - name: ccs-builder + emptyDir: {} + +--- +apiVersion: v1 +kind: Service +metadata: + name: org2-peer1 +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + - name: chaincode + port: 7052 + protocol: TCP + - name: operations + port: 9443 + protocol: TCP + selector: + app: org2-peer1 \ No newline at end of file diff --git a/test-network-k8s/kube/org2/org2-peer2.yaml b/test-network-k8s/kube/org2/org2-peer2.yaml new file mode 100644 index 00000000..c0df9b4e --- /dev/null +++ b/test-network-k8s/kube/org2/org2-peer2.yaml @@ -0,0 +1,89 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: org2-peer2-config +data: + FABRIC_CFG_PATH: /var/hyperledger/fabric/config + FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" + CORE_PEER_TLS_ENABLED: "true" + CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/signcerts/cert.pem + CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/keystore/server.key + CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/cacerts/org2-tls-ca.pem + CORE_PEER_ID: org2-peer2.org2.example.com + CORE_PEER_ADDRESS: org2-peer2:7051 + CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 + CORE_PEER_CHAINCODEADDRESS: org2-peer2:7052 + CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 + # bootstrap peer is the other peer in the same org + CORE_PEER_GOSSIP_BOOTSTRAP: org2-peer1:7051 + CORE_PEER_GOSSIP_EXTERNALENDPOINT: org2-peer2:7051 + CORE_PEER_LOCALMSPID: Org2MSP + CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/msp + CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 + CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org2-peer2.org2.example.com + CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org2-peer2.org2.example.com/snapshots + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org2-peer2 +spec: + replicas: 1 + selector: + matchLabels: + app: org2-peer2 + template: + metadata: + labels: + app: org2-peer2 + spec: + containers: + - name: main + image: hyperledger/fabric-peer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: org2-peer2-config + ports: + - containerPort: 7051 + - containerPort: 7052 + - containerPort: 9443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric/config + + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org2 + - name: fabric-config + configMap: + name: org2-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org2-peer2 +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + - name: chaincode + port: 7052 + protocol: TCP + - name: operations + port: 9443 + protocol: TCP + selector: + app: org2-peer2 \ No newline at end of file diff --git a/test-network-k8s/kube/org2/org2-tls-ca.yaml b/test-network-k8s/kube/org2/org2-tls-ca.yaml new file mode 100644 index 00000000..b28a7aa0 --- /dev/null +++ b/test-network-k8s/kube/org2/org2-tls-ca.yaml @@ -0,0 +1,65 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: org2-tls-ca +spec: + replicas: 1 + selector: + matchLabels: + app: org2-tls-ca + template: + metadata: + labels: + app: org2-tls-ca + spec: + containers: + - name: main + image: hyperledger/fabric-ca:1.5.2 + env: + - name: FABRIC_CA_SERVER_CA_NAME + value: "org2-tls-ca" + - name: FABRIC_CA_SERVER_DEBUG + value: "false" + - name: FABRIC_CA_SERVER_HOME + value: "/var/hyperledger/fabric-tls-ca-server" + - name: FABRIC_CA_CLIENT_HOME + value: "/var/hyperledger/fabric-ca-client" + ports: + - containerPort: 443 + volumeMounts: + - name: fabric-volume + mountPath: /var/hyperledger + - name: fabric-config + mountPath: /var/hyperledger/fabric-tls-ca-server/fabric-ca-server-config.yaml + subPath: fabric-tls-ca-server-config.yaml + readinessProbe: + tcpSocket: + port: 443 + initialDelaySeconds: 2 + periodSeconds: 5 + volumes: + - name: fabric-volume + persistentVolumeClaim: + claimName: fabric-org2 + - name: fabric-config + configMap: + name: org2-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: org2-tls-ca +spec: + ports: + - name: tls + port: 443 + protocol: TCP + selector: + app: org2-tls-ca \ No newline at end of file diff --git a/test-network-k8s/kube/pv-fabric-org0.yaml b/test-network-k8s/kube/pv-fabric-org0.yaml new file mode 100644 index 00000000..085872a4 --- /dev/null +++ b/test-network-k8s/kube/pv-fabric-org0.yaml @@ -0,0 +1,18 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: fabric-org0 +spec: + storageClassName: standard + accessModes: + - ReadWriteOnce + capacity: + storage: 2Gi + hostPath: + path: /var/hyperledger/example.com diff --git a/test-network-k8s/kube/pv-fabric-org1.yaml b/test-network-k8s/kube/pv-fabric-org1.yaml new file mode 100644 index 00000000..58de91af --- /dev/null +++ b/test-network-k8s/kube/pv-fabric-org1.yaml @@ -0,0 +1,18 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: fabric-org1 +spec: + storageClassName: standard + accessModes: + - ReadWriteOnce + capacity: + storage: 2Gi + hostPath: + path: /var/hyperledger/org1.example.com diff --git a/test-network-k8s/kube/pv-fabric-org2.yaml b/test-network-k8s/kube/pv-fabric-org2.yaml new file mode 100644 index 00000000..aa3660c7 --- /dev/null +++ b/test-network-k8s/kube/pv-fabric-org2.yaml @@ -0,0 +1,18 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: fabric-org2 +spec: + storageClassName: standard + accessModes: + - ReadWriteOnce + capacity: + storage: 2Gi + hostPath: + path: /var/hyperledger/org2.example.com diff --git a/test-network-k8s/kube/pvc-fabric-org0.yaml b/test-network-k8s/kube/pvc-fabric-org0.yaml new file mode 100644 index 00000000..c3d64208 --- /dev/null +++ b/test-network-k8s/kube/pvc-fabric-org0.yaml @@ -0,0 +1,17 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: fabric-org0 +spec: + volumeName: fabric-org0 + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/test-network-k8s/kube/pvc-fabric-org1.yaml b/test-network-k8s/kube/pvc-fabric-org1.yaml new file mode 100644 index 00000000..d06bc01c --- /dev/null +++ b/test-network-k8s/kube/pvc-fabric-org1.yaml @@ -0,0 +1,17 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: fabric-org1 +spec: + volumeName: fabric-org1 + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/test-network-k8s/kube/pvc-fabric-org2.yaml b/test-network-k8s/kube/pvc-fabric-org2.yaml new file mode 100644 index 00000000..40d2e48f --- /dev/null +++ b/test-network-k8s/kube/pvc-fabric-org2.yaml @@ -0,0 +1,17 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: fabric-org2 +spec: + volumeName: fabric-org2 + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/test-network-k8s/network b/test-network-k8s/network new file mode 100755 index 00000000..ecbef2a3 --- /dev/null +++ b/test-network-k8s/network @@ -0,0 +1,157 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# +set -o errexit + +# todo: better handling for input parameters. +# todo: skip storage volume init if deploying to a remote / cloud cluster (ICP IKS ROKS etc...) +# todo: for logging, set up a stack and allow multi-line status output codes +# todo: refactor - lots of for-org-in-0-to-2-... +# todo: find a better technique for passing input commands to a remote kube exec +# todo: register tls csr.hosts w/ kube DNS domain .NS.svc.cluster.local +# todo: user:pass auth for tls and ecert bootstrap admins. here and in the server-config.yaml +# todo: set tls.certfiles= ... arg in deployment env / yaml +# todo: refactor chaincode install to support other chaincode routines +# todo: actually compile the chaincode archive, rather than reading a pre-canned one from chaincode/*.tgz (use sha256 to get CC ID) +# todo: consider using templates for boilerplate network nodes (orderers, peers, ...) +# todo: allow the user to specify the chaincode name (hardcoded as 'basic') both in install and invoke/query +# todo: track down a nasty bug whereby the CA service endpoints (kube services) will occasionally reject TCP connections after network down/up. This is patched by introducing a 10s sleep after the deployments are up... +# todo: refactor query/invoke to specify chaincode name (-n param) + +FABRIC_VERSION=${TEST_NETWORK_FABRIC_VERSION:-2.3.2} +NETWORK_NAME=${TEST_NETWORK_NAME:-test-network} +CLUSTER_NAME=${TEST_NETWORK_KIND_CLUSTER_NAME:-kind} +NS=${TEST_NETWORK_KUBE_NAMESPACE:-${NETWORK_NAME}} +CHANNEL_NAME=${TEST_NETWORK_CHANNEL_NAME:-mychannel} +LOG_FILE=${TEST_NETWORK_LOG_FILE:-network.log} +DEBUG_FILE=${TEST_NETWORK_DEBUG_FILE:-network-debug.log} +CONTAINER_REGISTRY_NAME=${TEST_NETWORK_CONTAINER_REGISTRY_NAME:-kind-registry} +CONTAINER_REGISTRY_PORT=${TEST_NETWORK_CONTAINER_REGISTRY_PORT:-5000} +NGINX_HTTP_PORT=${TEST_NETWORK_INGRESS_HTTP_PORT:-80} +NGINX_HTTPS_PORT=${TEST_NETWORK_INGRESS_HTTPS_PORT:-443} +CHAINCODE_NAME=${TEST_NETWORK_CHAINCODE_NAME:-asset-transfer-basic} +CHAINCODE_IMAGE=${TEST_NETWORK_CHAINCODE_IMAGE:-ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic} +CHAINCODE_LABEL=${TEST_NETWORK_CHAINCODE_LABEL:-basic_1.0} + +# todo: more complicated config, as these bleed into the yaml descriptors (sed? kustomize? helm (no)? tkn? ansible?...) or other script locations +FABRIC_CA_VERSION=1.5.2 +TLSADMIN_AUTH=tlsadmin:tlsadminpw +RCAADMIN_AUTH=rcaadmin:rcaadminpw + +function print_help() { + echo todo: help output, parse mode, flags, env, etc. +} + +. scripts/utils.sh +. scripts/prereqs.sh +. scripts/kind.sh +. scripts/fabric_config.sh +. scripts/fabric_CAs.sh +. scripts/test_network.sh +. scripts/channel.sh +. scripts/chaincode.sh +. scripts/rest_sample.sh +. scripts/application_connection.sh + +# check for kind, kubectl, etc. +check_prereqs + +## Parse mode +if [[ $# -lt 1 ]] ; then + print_help + exit 0 +else + MODE=$1 + shift +fi + +# Initialize the logging system - control output to 'network.log' and everything else to 'network-debug.log' +logging_init + +if [ "${MODE}" == "kind" ]; then + log "Initializing KIND cluster \"${CLUSTER_NAME}\":" + kind_init + log "🏁 - Cluster is ready." + +elif [ "${MODE}" == "unkind" ]; then + log "Deleting cluster \"${CLUSTER_NAME}\":" + kind_unkind + log "🏁 - Cluster is gone." + +elif [ "${MODE}" == "up" ]; then + log "Launching network \"${NETWORK_NAME}\":" + network_up + log "🏁 - Network is ready." + +elif [ "${MODE}" == "down" ]; then + log "Shutting down test network \"${NETWORK_NAME}\":" + network_down + log "🏁 - Fabric network is down." + +elif [ "${MODE}" == "channel" ]; then + ACTION=$1 + shift + + if [ "${ACTION}" == "create" ]; then + log "Creating channel \"${CHANNEL_NAME}\":" + channel_up + log "🏁 - Channel is ready." + + else + print_help + exit 1 + fi + +elif [ "${MODE}" == "chaincode" ]; then + ACTION=$1 + shift + + if [ "${ACTION}" == "deploy" ]; then + log "Deploying chaincode \"${CHAINCODE_NAME}\":" + deploy_chaincode + log "🏁 - Chaincode is ready." + + elif [ "${ACTION}" == "install" ]; then + log "Installing chaincode \"${CHAINCODE_NAME}\":" + install_chaincode + log "🏁 - Chaincode is installed with CHAINCODE_ID=${CHAINCODE_ID}" + + elif [ "${ACTION}" == "activate" ]; then + log "Activating chaincode \"${CHAINCODE_NAME}\":" + activate_chaincode + log "🏁 - Chaincode is activated with CHAINCODE_ID=${CHAINCODE_ID}" + + elif [ "${ACTION}" == "invoke" ]; then + invoke_chaincode $@ 2>> ${LOG_FILE} + + elif [ "${ACTION}" == "query" ]; then + query_chaincode $@ >> ${LOG_FILE} + + elif [ "${ACTION}" == "metadata" ]; then + query_chaincode_metadata >> ${LOG_FILE} + else + print_help + exit 1 + fi + +elif [ "${MODE}" == "anchor" ]; then + update_anchor_peers $@ + +elif [ "${MODE}" == "rest-easy" ]; then + log "Launching fabric-rest-sample application:" + launch_rest_sample + log "🏁 - Fabric REST sample is ready." + +elif [ "${MODE}" == "application" ]; then + log "Getting application connection information:" + application_connection + log "🏁 - Output in...xxx" + +else + print_help + exit 1 +fi + diff --git a/test-network-k8s/scripts/application_connection.sh b/test-network-k8s/scripts/application_connection.sh new file mode 100755 index 00000000..3f73dd20 --- /dev/null +++ b/test-network-k8s/scripts/application_connection.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +function app_extract_MSP_archives() { + mkdir -p build/msp + set -ex + kubectl -n $NS exec deploy/org1-ecert-ca -- tar zcf - -C /var/hyperledger/fabric organizations/peerOrganizations/org1.example.com/msp | tar zxf - -C build/msp + kubectl -n $NS exec deploy/org2-ecert-ca -- tar zcf - -C /var/hyperledger/fabric organizations/peerOrganizations/org2.example.com/msp | tar zxf - -C build/msp + + kubectl -n $NS exec deploy/org1-ecert-ca -- tar zcf - -C /var/hyperledger/fabric organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp | tar zxf - -C build/msp + kubectl -n $NS exec deploy/org2-ecert-ca -- tar zcf - -C /var/hyperledger/fabric organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp | tar zxf - -C build/msp +} + +function app_one_line_pem { + echo "`awk 'NF {sub(/\\n/, ""); printf "%s\\\\\\\n",$0;}' $1`" +} + +function app_json_ccp { + local ORG=$1 + local PP=$(one_line_pem $2) + local CP=$(one_line_pem $3) + sed -e "s/\${ORG}/$ORG/" \ + -e "s#\${PEERPEM}#$PP#" \ + -e "s#\${CAPEM}#$CP#" \ + scripts/ccp-template.json +} + +function app_id { + local MSP=$1 + local CERT=$(one_line_pem $2) + local PK=$(one_line_pem $3) + + sed -e "s#\${CERTIFICATE}#$CERT#" \ + -e "s#\${PRIVATE_KEY}#$PK#" \ + -e "s#\${MSPID}#$MSP#" \ + scripts/appuser.id.template +} + +function construct_application_configmap() { + push_fn "Constructing application connection profiles" + + app_extract_MSP_archives + + mkdir -p build/application/wallet + mkdir -p build/application/gateways + + local peer_pem=build/msp/organizations/peerOrganizations/org1.example.com/msp/tlscacerts/org1-tls-ca.pem + local ca_pem=build/msp/organizations/peerOrganizations/org1.example.com/msp/cacerts/org1-ecert-ca.pem + + echo "$(json_ccp 1 $peer_pem $ca_pem)" > build/application/gateways/org1_ccp.json + + peer_pem=build/msp/organizations/peerOrganizations/org2.example.com/msp/tlscacerts/org2-tls-ca.pem + ca_pem=build/msp/organizations/peerOrganizations/org2.example.com/msp/cacerts/org2-ecert-ca.pem + + echo "$(json_ccp 2 $peer_pem $ca_pem)" > build/application/gateways/org2_ccp.json + + local cert=build/msp/organizations/peerOrganizations/org1.example.com/users/Admin\@org1.example.com/msp/signcerts/cert.pem + local pk=build/msp/organizations/peerOrganizations/org1.example.com/users/Admin\@org1.example.com/msp/keystore/server.key + + echo "$(app_id Org1MSP $cert $pk)" > build/application/wallet/appuser_org1.id + + local cert=build/msp/organizations/peerOrganizations/org2.example.com/users/Admin\@org2.example.com/msp/signcerts/cert.pem + local pk=build/msp/organizations/peerOrganizations/org2.example.com/users/Admin\@org2.example.com/msp/keystore/server.key + + echo "$(app_id Org2MSP $cert $pk)" > build/application/wallet/appuser_org2.id + + kubectl -n $NS delete configmap app-fabric-tls-v1-map || log "app-fabric-tls-v1-map not present" + kubectl -n $NS create configmap app-fabric-tls-v1-map --from-file=./build/msp/organizations/peerOrganizations/org1.example.com/msp/tlscacerts + + kubectl -n $NS delete configmap app-fabric-ids-v1-map || log "app-fabric-id-v1-map not present" + kubectl -n $NS create configmap app-fabric-ids-v1-map --from-file=./build/application/wallet + + kubectl -n $NS delete configmap app-fabric-ccp-v1-map || log "app-fabric-id-v1-map not present" + kubectl -n $NS create configmap app-fabric-ccp-v1-map --from-file=./build/application/gateways + +cat < build/app-fabric-org1-v1-map.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: app-fabric-org1-v1-map +data: + fabric_channel: ${CHANNEL_NAME} + fabric_contract: ${CHAINCODE_NAME} + fabric_wallet_dir: /fabric/application/wallet + fabric_gateway_hostport: org1-peer1:7051 + fabric_gateway_sslHostOverride: org1-peer1 + fabric_user: appuser_org1 + fabric_gateway_tlsCertPath: /fabric/tlscacerts/org1-tls-ca.pem +EOF + + kubectl -n $NS apply -f build/app-fabric-org1-v1-map.yaml + + # todo: could add the second org here + + pop_fn +} + + +function application_connection() { + + construct_application_configmap + + log "" + log "Config Maps created for the application" + log "To deploy your application updated the image name and issue these commands" + log "" + log "kubectl -n $NS apply -f kube/application-deployment.yaml" + log "kubectl -n $NS rollout status deploy/application-deployment" + +} \ No newline at end of file diff --git a/test-network-k8s/scripts/appuser.id.template b/test-network-k8s/scripts/appuser.id.template new file mode 100644 index 00000000..1c67576c --- /dev/null +++ b/test-network-k8s/scripts/appuser.id.template @@ -0,0 +1,9 @@ +{ + "credentials": { + "certificate": "${CERTIFICATE}", + "privateKey": "${PRIVATE_KEY}" + }, + "mspId": "${MSPID}", + "type": "X.509", + "version": 1 +} \ No newline at end of file diff --git a/test-network-k8s/scripts/ccp-template.json b/test-network-k8s/scripts/ccp-template.json new file mode 100755 index 00000000..4bd0a26e --- /dev/null +++ b/test-network-k8s/scripts/ccp-template.json @@ -0,0 +1,49 @@ +{ + "name": "test-network-org${ORG}", + "version": "1.0.0", + "client": { + "organization": "Org${ORG}", + "connection": { + "timeout": { + "peer": { + "endorser": "300" + } + } + } + }, + "organizations": { + "Org${ORG}": { + "mspid": "Org${ORG}MSP", + "peers": [ + "org${ORG}-peer1" + ], + "certificateAuthorities": [ + "org${ORG}-ecert-ca" + ] + } + }, + "peers": { + "org${ORG}-peer1": { + "url": "grpcs://org${ORG}-peer1:7051", + "tlsCACerts": { + "pem": "${PEERPEM}" + }, + "grpcOptions": { + "ssl-target-name-override": "org${ORG}-peer1", + "hostnameOverride": "org${ORG}-peer1" + } + } + }, + "certificateAuthorities": { + "org${ORG}-ecert-ca": { + "url": "https://org${ORG}-ecert-ca", + "caName": "org${ORG}-ecert-ca", + "tlsCACerts": { + "pem": ["${CAPEM}"] + }, + "httpOptions": { + "verify": false + } + } + } +} diff --git a/test-network-k8s/scripts/chaincode.sh b/test-network-k8s/scripts/chaincode.sh new file mode 100755 index 00000000..c0fec221 --- /dev/null +++ b/test-network-k8s/scripts/chaincode.sh @@ -0,0 +1,172 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +function package_chaincode_for() { + local org=$1 + local cc_folder="chaincode/${CHAINCODE_NAME}" + local build_folder="build/chaincode" + local cc_archive="${build_folder}/${CHAINCODE_NAME}.tgz" + push_fn "Packaging chaincode folder ${cc_folder}" + + mkdir -p ${build_folder} + + tar -C ${cc_folder} -zcf ${cc_folder}/code.tar.gz connection.json + tar -C ${cc_folder} -zcf ${cc_archive} code.tar.gz metadata.json + + rm ${cc_folder}/code.tar.gz + + pop_fn +} + +# Copy the chaincode archive from the local host to the org admin +function transfer_chaincode_archive_for() { + local org=$1 + local cc_archive="build/chaincode/${CHAINCODE_NAME}.tgz" + push_fn "Transferring chaincode archive to ${org}" + + # Like kubectl cp, but targeted to a deployment rather than an individual pod. + tar cf - ${cc_archive} | kubectl -n $NS exec -i deploy/${org}-admin-cli -c main -- tar xvf - + + pop_fn +} + +function install_chaincode_for() { + local org=$1 + push_fn "Installing chaincode for org ${org}" + + # Install the chaincode + echo 'set -x + export CORE_PEER_ADDRESS='${org}'-peer1:7051 + peer lifecycle chaincode install build/chaincode/'${CHAINCODE_NAME}'.tgz + ' | exec kubectl -n $NS exec deploy/${org}-admin-cli -c main -i -- /bin/bash + + pop_fn +} + +function launch_chaincode_service() { + local org=$1 + local cc_id=$2 + local cc_image=$3 + push_fn "Launching chaincode container \"${cc_image}\"" + + # The chaincode endpoint needs to have the generated chaincode ID available in the environment. + # This could be from a config map, a secret, or by directly editing the deployment spec. Here we'll keep + # things simple by using sed to substitute script variables into a yaml template. + cat kube/${org}/${org}-cc-template.yaml \ + | sed 's,{{CHAINCODE_NAME}},'${CHAINCODE_NAME}',g' \ + | sed 's,{{CHAINCODE_ID}},'${cc_id}',g' \ + | sed 's,{{CHAINCODE_IMAGE}},'${cc_image}',g' \ + | exec kubectl -n $NS apply -f - + + kubectl -n $NS rollout status deploy/${org}-cc-${CHAINCODE_NAME} + + pop_fn +} + +function activate_chaincode_for() { + local org=$1 + local cc_id=$2 + push_fn "Activating chaincode ${CHAINCODE_ID}" + + echo 'set -x + 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 + ' | exec kubectl -n $NS exec deploy/${org}-admin-cli -c main -i -- /bin/bash + + pop_fn +} + +function query_chaincode() { + set -x + # todo: mangle additional $@ parameters with bash escape quotations + echo ' + export CORE_PEER_ADDRESS=org1-peer1:7051 + peer chaincode query -n '${CHAINCODE_NAME}' -C '${CHANNEL_NAME}' -c '"'$@'"' + ' | exec kubectl -n $NS exec deploy/org1-admin-cli -c main -i -- /bin/bash +} + +function query_chaincode_metadata() { + set -x + local args='{"Args":["org.hyperledger.fabric:GetMetadata"]}' + # todo: mangle additional $@ parameters with bash escape quotations + echo ' + export CORE_PEER_ADDRESS=org1-peer1:7051 + peer chaincode query -n '${CHAINCODE_NAME}' -C '${CHANNEL_NAME}' -c '"'$args'"' + ' | exec kubectl -n $NS exec deploy/org1-admin-cli -c main -i -- /bin/bash +} + +function invoke_chaincode() { + # set -x + # todo: mangle additional $@ parameters with bash escape quotations + echo ' + export CORE_PEER_ADDRESS=org1-peer1:7051 + peer chaincode \ + invoke \ + -o org0-orderer1:6050 \ + --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem \ + -n '${CHAINCODE_NAME}' \ + -C '${CHANNEL_NAME}' \ + -c '"'$@'"' + ' | exec kubectl -n $NS exec deploy/org1-admin-cli -c main -i -- /bin/bash + + sleep 2 +} + +# Normally the chaincode ID is emitted by the peer install command. In this case, we'll generate the +# package ID as the sha-256 checksum of the chaincode archive. +function set_chaincode_id() { + local cc_sha256=$(shasum -a 256 build/chaincode/${CHAINCODE_NAME}.tgz | tr -s ' ' | cut -d ' ' -f 1) + + CHAINCODE_ID=${CHAINCODE_LABEL}:${cc_sha256} +} + +# Package and install the chaincode, but do not activate. +function install_chaincode() { + local org=org1 + + package_chaincode_for ${org} + transfer_chaincode_archive_for ${org} + install_chaincode_for ${org} + + set_chaincode_id +} + +# Activate the installed chaincode but do not package/install a new archive. +function activate_chaincode() { + set -x + + set_chaincode_id + activate_chaincode_for org1 $CHAINCODE_ID +} + +# Install, launch, and activate the chaincode +function deploy_chaincode() { + set -x + + install_chaincode + launch_chaincode_service org1 $CHAINCODE_ID $CHAINCODE_IMAGE + activate_chaincode +} + diff --git a/test-network-k8s/scripts/channel.sh b/test-network-k8s/scripts/channel.sh new file mode 100755 index 00000000..f8a79555 --- /dev/null +++ b/test-network-k8s/scripts/channel.sh @@ -0,0 +1,201 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +function create_channel_org_MSP() { + local org=$1 + local org_type=$2 + local ecert_ca=${org}-ecert-ca + + echo 'set -x + + mkdir -p /var/hyperledger/fabric/organizations/'${org_type}'Organizations/'${org}'.example.com/msp/cacerts + cp \ + $FABRIC_CA_CLIENT_HOME/'${ecert_ca}'/rcaadmin/msp/cacerts/'${ecert_ca}'.pem \ + /var/hyperledger/fabric/organizations/'${org_type}'Organizations/'${org}'.example.com/msp/cacerts + + mkdir -p /var/hyperledger/fabric/organizations/'${org_type}'Organizations/'${org}'.example.com/msp/tlscacerts + cp \ + $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp/cacerts/'${org}'-tls-ca.pem \ + /var/hyperledger/fabric/organizations/'${org_type}'Organizations/'${org}'.example.com/msp/tlscacerts + + echo "NodeOUs: + Enable: true + ClientOUIdentifier: + Certificate: cacerts/'${ecert_ca}'.pem + OrganizationalUnitIdentifier: client + PeerOUIdentifier: + Certificate: cacerts/'${ecert_ca}'.pem + OrganizationalUnitIdentifier: peer + AdminOUIdentifier: + Certificate: cacerts/'${ecert_ca}'.pem + OrganizationalUnitIdentifier: admin + OrdererOUIdentifier: + Certificate: cacerts/'${ecert_ca}'.pem + OrganizationalUnitIdentifier: orderer "> /var/hyperledger/fabric/organizations/'${org_type}'Organizations/'${org}'.example.com/msp/config.yaml + + ' | exec kubectl -n $NS exec deploy/${ecert_ca} -i -- /bin/sh +} + +function create_channel_MSP() { + push_fn "Creating channel MSP" + + create_channel_org_MSP org0 orderer + create_channel_org_MSP org1 peer + create_channel_org_MSP org2 peer + + pop_fn +} + +function aggregate_channel_MSP() { + push_fn "Aggregating channel MSP" + + rm -rf ./build/msp/ + mkdir -p ./build/msp + + kubectl -n $NS exec deploy/org0-ecert-ca -- tar zcvf - -C /var/hyperledger/fabric organizations/ordererOrganizations/org0.example.com/msp > build/msp/msp-org0.example.com.tgz + kubectl -n $NS exec deploy/org1-ecert-ca -- tar zcvf - -C /var/hyperledger/fabric organizations/peerOrganizations/org1.example.com/msp > build/msp/msp-org1.example.com.tgz + kubectl -n $NS exec deploy/org2-ecert-ca -- tar zcvf - -C /var/hyperledger/fabric organizations/peerOrganizations/org2.example.com/msp > build/msp/msp-org2.example.com.tgz + + kubectl -n $NS delete configmap msp-config || true + kubectl -n $NS create configmap msp-config --from-file=build/msp/ + + pop_fn +} + +function launch_admin_CLIs() { + push_fn "Launching admin CLIs" + + cat kube/org0/org0-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - + cat kube/org1/org1-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - + cat kube/org2/org2-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - + + kubectl -n $NS rollout status deploy/org0-admin-cli + kubectl -n $NS rollout status deploy/org1-admin-cli + kubectl -n $NS rollout status deploy/org2-admin-cli + + pop_fn +} + +function create_genesis_block() { + push_fn "Creating channel \"${CHANNEL_NAME}\"" + + echo 'set -x + configtxgen -profile TwoOrgsApplicationGenesis -channelID '${CHANNEL_NAME}' -outputBlock genesis_block.pb + # configtxgen -inspectBlock genesis_block.pb + + osnadmin channel join --orderer-address org0-orderer1:9443 --channelID '${CHANNEL_NAME}' --config-block genesis_block.pb + osnadmin channel join --orderer-address org0-orderer2:9443 --channelID '${CHANNEL_NAME}' --config-block genesis_block.pb + osnadmin channel join --orderer-address org0-orderer3:9443 --channelID '${CHANNEL_NAME}' --config-block genesis_block.pb + + ' | exec kubectl -n $NS exec deploy/org0-admin-cli -i -- /bin/bash + + # todo: readiness / liveiness equivalent for channel ? Needs a little bit to settle before peers can join. + sleep 10 + + pop_fn +} + +function join_org_peers() { + local org=$1 + push_fn "Joining ${org} peers to channel \"${CHANNEL_NAME}\"" + + echo 'set -x + # Fetch the genesis block from an orderer + peer channel \ + fetch oldest \ + genesis_block.pb \ + -c '${CHANNEL_NAME}' \ + -o org0-orderer1:6050 \ + --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem + + # Join peer1 to the channel. + CORE_PEER_ADDRESS='${org}'-peer1:7051 \ + peer channel \ + join \ + -b genesis_block.pb \ + -o org0-orderer1:6050 \ + --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem + + # Join peer2 to the channel. + CORE_PEER_ADDRESS='${org}'-peer2:7051 \ + peer channel \ + join \ + -b genesis_block.pb \ + -o org0-orderer1:6050 \ + --tls --cafile /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem + + ' | exec kubectl -n $NS exec deploy/${org}-admin-cli -i -- /bin/bash + + pop_fn +} + +function join_peers() { + join_org_peers org1 + join_org_peers org2 +} + +# Copy the scripts/anchor_peers.sh to a remote volume +function push_anchor_peer_script() { + local org=$1 + + tar cf - scripts/ | kubectl -n $NS exec -i -c main deploy/${org}-admin-cli -- tar xf - -C /var/hyperledger/fabric +} + +verify_result() { + if [ $1 -ne 0 ]; then + echo $2 + exit $1 + fi +} + +# Launch the anchor peer update script on a remote org admin CLI +function invoke_anchor_peer_update() { + local org_num=$1 + local peer_name=$2 + + kubectl exec \ + -n $NS \ + -c main \ + deploy/org${org_num}-admin-cli \ + -i \ + /bin/bash -c "/var/hyperledger/fabric/scripts/set_anchor_peer.sh ${org_num} ${CHANNEL_NAME} ${peer_name}" + + verify_result $? "Error updating anchor peer for org ${org_num}" +} + +# +# To update the anchor peers we will need to execute a script on each of the peer admin CLI containers. These +# commands can be individually piped into kubectl exec ... but it will be simpler if we transfer the anchor +# peer update script over to the org volume and then trigger it from kubectl. +# +function update_anchor_peers() { + local peer_name=$1 + push_fn "Updating anchor peers to ${peer_name}" + + push_anchor_peer_script org1 + push_anchor_peer_script org2 + + invoke_anchor_peer_update 1 ${peer_name} + invoke_anchor_peer_update 2 ${peer_name} + + pop_fn +} + +function channel_up() { + + create_channel_MSP + aggregate_channel_MSP + launch_admin_CLIs + + create_genesis_block + join_peers + + # peer1 was set as the anchor peer in configtx.yaml. Setting this again will force an + # error to be returned from the channel up. We might want to render the warning in + # this case to indicate that the call was made but had a nonzero exit. + # update_anchor_peers peer1 +} \ No newline at end of file diff --git a/test-network-k8s/scripts/fabric_CAs.sh b/test-network-k8s/scripts/fabric_CAs.sh new file mode 100755 index 00000000..6ec4708a --- /dev/null +++ b/test-network-k8s/scripts/fabric_CAs.sh @@ -0,0 +1,137 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +function launch_TLS_CAs() { + push_fn "Launching TLS CAs" + + kubectl -n $NS apply -f kube/org0/org0-tls-ca.yaml + kubectl -n $NS apply -f kube/org1/org1-tls-ca.yaml + kubectl -n $NS apply -f kube/org2/org2-tls-ca.yaml + + kubectl -n $NS rollout status deploy/org0-tls-ca + kubectl -n $NS rollout status deploy/org1-tls-ca + kubectl -n $NS rollout status deploy/org2-tls-ca + + # todo: this papers over a nasty bug whereby the CAs are ready, but sporadically refuse connections after a down / up + sleep 10 + + pop_fn +} + +function launch_ECert_CAs() { + push_fn "Launching ECert CAs" + + kubectl -n $NS apply -f kube/org0/org0-ecert-ca.yaml + kubectl -n $NS apply -f kube/org1/org1-ecert-ca.yaml + kubectl -n $NS apply -f kube/org2/org2-ecert-ca.yaml + + kubectl -n $NS rollout status deploy/org0-ecert-ca + kubectl -n $NS rollout status deploy/org1-ecert-ca + kubectl -n $NS rollout status deploy/org2-ecert-ca + + # todo: this papers over a nasty bug whereby the CAs are ready, but sporadically refuse connections after a down / up + sleep 10 + + pop_fn +} + +# Enroll bootstrap user with TLS CA +# https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#enroll-bootstrap-user-with-tls-ca +function enroll_bootstrap_TLS_CA_user() { + local org=$1 + local auth=$2 + local tlsca=${org}-tls-ca + + # todo: get rid of export here - put in yaml + + echo 'set -x + + mkdir -p $FABRIC_CA_CLIENT_HOME/tls-root-cert + cp $FABRIC_CA_SERVER_HOME/ca-cert.pem $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem + + fabric-ca-client enroll \ + --url https://'$auth'@'${tlsca}' \ + --tls.certfiles $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem \ + --csr.hosts '${tlsca}' \ + --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + + ' | exec kubectl -n $NS exec deploy/${tlsca} -i -- /bin/sh +} + +function enroll_bootstrap_TLS_CA_users() { + push_fn "Enrolling bootstrap TLS CA users" + + enroll_bootstrap_TLS_CA_user org0 $TLSADMIN_AUTH + enroll_bootstrap_TLS_CA_user org1 $TLSADMIN_AUTH + enroll_bootstrap_TLS_CA_user org2 $TLSADMIN_AUTH + + pop_fn +} + +function register_enroll_ECert_CA_bootstrap_user() { + local org=$1 + local tlsauth=$2 + local tlsca=${org}-tls-ca + local ecertca=${org}-ecert-ca + + echo 'set -x + + fabric-ca-client register \ + --id.name rcaadmin \ + --id.secret rcaadminpw \ + --url https://'${tlsca}' \ + --tls.certfiles $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem \ + --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + + fabric-ca-client enroll \ + --url https://'${tlsauth}'@'${tlsca}' \ + --tls.certfiles $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem \ + --csr.hosts '${ecertca}' \ + --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/rcaadmin/msp + + # Important: the rcaadmin signing certificate is referenced by the ECert CA FABRIC_CA_SERVER_TLS_CERTFILE config attribute. + # For simplicity, reference the key at a fixed, known location + cp $FABRIC_CA_CLIENT_HOME/tls-ca/rcaadmin/msp/keystore/*_sk $FABRIC_CA_CLIENT_HOME/tls-ca/rcaadmin/msp/keystore/key.pem + + ' | exec kubectl -n $NS exec deploy/${tlsca} -i -- /bin/sh +} + +# https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/cadeploy.html#register-and-enroll-the-organization-ca-bootstrap-identity-with-the-tls-ca +function register_enroll_ECert_CA_bootstrap_users() { + push_fn "Registering and enrolling ECert CA bootstrap users" + + register_enroll_ECert_CA_bootstrap_user org0 $TLSADMIN_AUTH + register_enroll_ECert_CA_bootstrap_user org1 $TLSADMIN_AUTH + register_enroll_ECert_CA_bootstrap_user org2 $TLSADMIN_AUTH + + pop_fn +} + +function enroll_bootstrap_ECert_CA_user() { + local org=$1 + local auth=$2 + local ecert_ca=${org}-ecert-ca + + echo 'set -x + + fabric-ca-client enroll \ + --url https://'${auth}'@'${ecert_ca}' \ + --tls.certfiles $FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem \ + --mspdir $FABRIC_CA_CLIENT_HOME/'${ecert_ca}'/rcaadmin/msp + + ' | exec kubectl -n $NS exec deploy/${ecert_ca} -i -- /bin/sh +} + +function enroll_bootstrap_ECert_CA_users() { + push_fn "Enrolling bootstrap ECert CA users" + + enroll_bootstrap_ECert_CA_user org0 $RCAADMIN_AUTH + enroll_bootstrap_ECert_CA_user org1 $RCAADMIN_AUTH + enroll_bootstrap_ECert_CA_user org2 $RCAADMIN_AUTH + + pop_fn +} \ No newline at end of file diff --git a/test-network-k8s/scripts/fabric_config.sh b/test-network-k8s/scripts/fabric_config.sh new file mode 100755 index 00000000..03ef9d9e --- /dev/null +++ b/test-network-k8s/scripts/fabric_config.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +function init_namespace() { + push_fn "Creating namespace \"$NS\"" + + kubectl create namespace $NS || true + + pop_fn +} + +function init_storage_volumes() { + push_fn "Provisioning volume storage" + + kubectl create -f kube/pv-fabric-org0.yaml || true + kubectl create -f kube/pv-fabric-org1.yaml || true + kubectl create -f kube/pv-fabric-org2.yaml || true + + kubectl -n $NS create -f kube/pvc-fabric-org0.yaml || true + kubectl -n $NS create -f kube/pvc-fabric-org1.yaml || true + kubectl -n $NS create -f kube/pvc-fabric-org2.yaml || true + + pop_fn +} + +function load_org_config() { + push_fn "Creating fabric config maps" + + kubectl -n $NS delete configmap org0-config || true + kubectl -n $NS delete configmap org1-config || true + kubectl -n $NS delete configmap org2-config || true + + kubectl -n $NS create configmap org0-config --from-file=config/org0 + kubectl -n $NS create configmap org1-config --from-file=config/org1 + kubectl -n $NS create configmap org2-config --from-file=config/org2 + + pop_fn +} \ No newline at end of file diff --git a/test-network-k8s/scripts/kind.sh b/test-network-k8s/scripts/kind.sh new file mode 100755 index 00000000..1784204d --- /dev/null +++ b/test-network-k8s/scripts/kind.sh @@ -0,0 +1,134 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +function pull_docker_images() { + push_fn "Pulling docker images for Fabric ${FABRIC_VERSION}" + + docker pull hyperledger/fabric-ca:$FABRIC_CA_VERSION + docker pull hyperledger/fabric-orderer:$FABRIC_VERSION + docker pull hyperledger/fabric-peer:$FABRIC_VERSION + docker pull hyperledger/fabric-tools:$FABRIC_VERSION + + pop_fn +} + +function apply_nginx_ingress() { + push_fn "Launching Nginx ingress controller" + + # This ingress-nginx.yaml was generated 9/24 from https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml + # with modifications for ssl-passthrough required to launch IBP-support with the nginx ingress. + # It may be preferable to always load from the remote mainline? + # kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml + kubectl apply -f kube/ingress-nginx.yaml + + pop_fn +} + +function kind_create() { + push_fn "Creating cluster \"${CLUSTER_NAME}\"" + + # todo: always delete? Maybe return no-op if the cluster already exists? + kind delete cluster --name $CLUSTER_NAME + + local reg_name=${CONTAINER_REGISTRY_NAME} + local reg_port=${CONTAINER_REGISTRY_PORT} + local ingress_http_port=${NGINX_HTTP_PORT} + local ingress_https_port=${NGINX_HTTPS_PORT} + + cat </dev/null || true)" + if [ "${running}" != 'true' ]; then + docker run \ + -d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" \ + registry:2 + fi + + # connect the registry to the cluster network + # (the network may already be connected) + docker network connect "kind" "${reg_name}" || true + + # Document the local registry + # https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry + cat < /dev/null + if [[ $? -ne 0 ]]; then + echo "No 'docker' binary available? (https://www.docker.com)" + exit 1 + fi + + kind version > /dev/null + if [[ $? -ne 0 ]]; then + echo "No 'kind' binary available? (https://kind.sigs.k8s.io/docs/user/quick-start/#installation)" + exit 1 + fi + + kubectl > /dev/null + if [[ $? -ne 0 ]]; then + echo "No 'kubectl' binary available? (https://kubernetes.io/docs/tasks/tools/)" + exit 1 + fi +} \ No newline at end of file diff --git a/test-network-k8s/scripts/rest_sample.sh b/test-network-k8s/scripts/rest_sample.sh new file mode 100755 index 00000000..fe397164 --- /dev/null +++ b/test-network-k8s/scripts/rest_sample.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +function extract_MSP_archives() { + mkdir -p build/msp + + kubectl -n $NS exec deploy/org1-ecert-ca -- tar zcf - -C /var/hyperledger/fabric organizations/peerOrganizations/org1.example.com/msp | tar zxf - -C build/msp + kubectl -n $NS exec deploy/org2-ecert-ca -- tar zcf - -C /var/hyperledger/fabric organizations/peerOrganizations/org2.example.com/msp | tar zxf - -C build/msp + + kubectl -n $NS exec deploy/org1-ecert-ca -- tar zcf - -C /var/hyperledger/fabric organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp | tar zxf - -C build/msp + kubectl -n $NS exec deploy/org2-ecert-ca -- tar zcf - -C /var/hyperledger/fabric organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp | tar zxf - -C build/msp +} + +function one_line_pem { + echo "`awk 'NF {sub(/\\n/, ""); printf "%s\\\\\\\n",$0;}' $1`" +} + +function json_ccp { + local ORG=$1 + local PP=$(one_line_pem $2) + local CP=$(one_line_pem $3) + sed -e "s/\${ORG}/$ORG/" \ + -e "s#\${PEERPEM}#$PP#" \ + -e "s#\${CAPEM}#$CP#" \ + scripts/ccp-template.json +} + +function construct_rest_sample_configmap() { + push_fn "Constructing fabric-rest-sample connection profiles" + + extract_MSP_archives + + mkdir -p build/fabric-rest-sample-config + + local peer_pem=build/msp/organizations/peerOrganizations/org1.example.com/msp/tlscacerts/org1-tls-ca.pem + local ca_pem=build/msp/organizations/peerOrganizations/org1.example.com/msp/cacerts/org1-ecert-ca.pem + + echo "$(json_ccp 1 $peer_pem $ca_pem)" > build/fabric-rest-sample-config/HLF_CONNECTION_PROFILE_ORG1 + + peer_pem=build/msp/organizations/peerOrganizations/org2.example.com/msp/tlscacerts/org2-tls-ca.pem + ca_pem=build/msp/organizations/peerOrganizations/org2.example.com/msp/cacerts/org2-ecert-ca.pem + + echo "$(json_ccp 2 $peer_pem $ca_pem)" > build/fabric-rest-sample-config/HLF_CONNECTION_PROFILE_ORG2 + + cat build/msp/organizations/peerOrganizations/org1.example.com/users/Admin\@org1.example.com/msp/signcerts/cert.pem > build/fabric-rest-sample-config/HLF_CERTIFICATE_ORG1 + cat build/msp/organizations/peerOrganizations/org2.example.com/users/Admin\@org2.example.com/msp/signcerts/cert.pem > build/fabric-rest-sample-config/HLF_CERTIFICATE_ORG2 + + cat build/msp/organizations/peerOrganizations/org1.example.com/users/Admin\@org1.example.com/msp/keystore/server.key > build/fabric-rest-sample-config/HLF_PRIVATE_KEY_ORG1 + cat build/msp/organizations/peerOrganizations/org2.example.com/users/Admin\@org2.example.com/msp/keystore/server.key > build/fabric-rest-sample-config/HLF_PRIVATE_KEY_ORG2 + + kubectl -n $NS delete configmap fabric-rest-sample-config || true + kubectl -n $NS create configmap fabric-rest-sample-config --from-file=build/fabric-rest-sample-config/ + + pop_fn +} + +# todo: Make sure to port this to IKS / ICP +function ensure_rest_sample_image() { + push_fn "Ensuring fabric-rest-sample image" + + # todo: apply a tag / label to avoid pulling :latest from ghcr.io + + pop_fn 0 +} + +function rollout_rest_sample() { + push_fn "Starting fabric-rest-sample" + + kubectl -n $NS apply -f kube/fabric-rest-sample.yaml + kubectl -n $NS rollout status deploy/fabric-rest-sample + + pop_fn +} + +function launch_rest_sample() { + ensure_rest_sample_image + construct_rest_sample_configmap + rollout_rest_sample + + log "" + log "The fabric-rest-sample has started. See https://github.com/hyperledgendary/fabric-rest-sample/tree/main/asset-transfer-basic/rest-api-typescript#rest-api for additional usage." + log "To access the endpoint:" + log "" + log "export SAMPLE_APIKEY=97834158-3224-4CE7-95F9-A148C886653E" + log 'curl -s --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost/api/assets' + log "" +} \ No newline at end of file diff --git a/test-network-k8s/scripts/set_anchor_peer.sh b/test-network-k8s/scripts/set_anchor_peer.sh new file mode 100755 index 00000000..59551f5e --- /dev/null +++ b/test-network-k8s/scripts/set_anchor_peer.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +function fetch_channel_config() { + local output=$1 + + echo "Fetching the most recent configuration block for channel ${CHANNEL_NAME}" + peer channel \ + fetch config config_block.pb \ + -o org0-orderer1:6050 \ + -c ${CHANNEL_NAME} \ + --tls --cafile ${ORDERER_TLS_CA_FILE} + + echo "Decoding config block to JSON and isolating config to ${output}" + configtxlator proto_decode \ + --input config_block.pb \ + --type common.Block \ + | jq .data.data[0].payload.data.config > ${output} +} + +verify_result() { + if [ $1 -ne 0 ]; then + echo $2 + exit $1 + fi +} + +function create_config_update() { + local original=$1 + local modified=$2 + local output=$3 + + configtxlator proto_encode --input "${original}" --type common.Config > original_config.pb + configtxlator proto_encode --input "${modified}" --type common.Config > modified_config.pb + + # returns non-zero if no updates were detected between current and new config + configtxlator compute_update --channel_id "${CHANNEL_NAME}" --original original_config.pb --updated modified_config.pb > config_update.pb + if [ $? -ne 0 ]; then + echo "Anchor peer has already been set to ${ANCHOR_PEER_HOST}:${ANCHOR_PEER_PORT} - no update required." + return 1 + fi + + configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate > config_update.json + echo '{"payload":{"header":{"channel_header":{"channel_id":"'${CHANNEL_NAME}'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json + configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope > ${output} + + return 0 +} + +function create_anchor_peer_update() { + echo "Generating anchor peer update transaction for Org${ORG_NUM} on channel ${CHANNEL_NAME}" + fetch_channel_config config.json + + set -x + # Modify the configuration to append the anchor peer + jq '.channel_group.groups.Application.groups.'${CORE_PEER_LOCALMSPID}'.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "'${ANCHOR_PEER_HOST}'","port": '${ANCHOR_PEER_PORT}'}]},"version": "0"}}' config.json > modified_config.json + { set +x; } 2>/dev/null + + # Compute a config update, based on the differences between + # config.json and modified_config.json, write + # it as a transaction to anchors.tx + create_config_update config.json modified_config.json anchors.tx + return $? +} + +function update_anchor_peer() { + peer channel \ + update -f anchors.tx \ + -o org0-orderer1:6050 \ + -c ${CHANNEL_NAME} \ + --tls --cafile ${ORDERER_TLS_CA_FILE} >& log.txt + + res=$? + cat log.txt + + verify_result $res "Anchor peer update failed" + + echo "Anchor peer set for org ${ORG_NAME} on channel ${CHANNEL_NAME} to ${ANCHOR_PEER_HOST}:${ANCHOR_PEER_PORT}" +} + +function set_anchor_peer() { + echo "Updating org ${ORG_NUM} anchor peer for channel ${CHANNEL_NAME} to ${ANCHOR_PEER_HOST}:${ANCHOR_PEER_PORT}" + + create_anchor_peer_update + res=$? + + if [ $res -eq 0 ]; then + update_anchor_peer + fi +} + +set -x + +ORG_NUM=$1 +CHANNEL_NAME=$2 +PEER_NAME=$3 +ORG_NAME="org${ORG_NUM}" +ANCHOR_PEER_HOST=${ORG_NAME}-${PEER_NAME} +ANCHOR_PEER_PORT=7051 +ORDERER_TLS_CA_FILE=/var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/msp/tlscacerts/org0-tls-ca.pem + +export CORE_PEER_LOCALMSPID="Org${ORG_NUM}MSP" + +set_anchor_peer + +{ set +x; } 2>/dev/null diff --git a/test-network-k8s/scripts/test_network.sh b/test-network-k8s/scripts/test_network.sh new file mode 100755 index 00000000..a0a0c87a --- /dev/null +++ b/test-network-k8s/scripts/test_network.sh @@ -0,0 +1,259 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +# todo: oof this is rough. + + +function launch() { + local yaml=$1 + cat ${yaml} | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - +} + +function launch_orderers() { + push_fn "Launching orderers" + + launch kube/org0/org0-orderer1.yaml + launch kube/org0/org0-orderer2.yaml + launch kube/org0/org0-orderer3.yaml + + kubectl -n $NS rollout status deploy/org0-orderer1 + kubectl -n $NS rollout status deploy/org0-orderer2 + kubectl -n $NS rollout status deploy/org0-orderer3 + + pop_fn +} + +function launch_peers() { + push_fn "Launching peers" + + launch kube/org1/org1-peer1.yaml + launch kube/org1/org1-peer2.yaml + launch kube/org2/org2-peer1.yaml + launch kube/org2/org2-peer2.yaml + + kubectl -n $NS rollout status deploy/org1-peer1 + kubectl -n $NS rollout status deploy/org1-peer2 + kubectl -n $NS rollout status deploy/org2-peer1 + kubectl -n $NS rollout status deploy/org2-peer2 + + pop_fn +} + +function create_org0_local_MSP() { + echo 'set -x + export FABRIC_CA_CLIENT_HOME=/var/hyperledger/fabric-ca-client + export FABRIC_CA_CLIENT_TLS_CERTFILES=$FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem + + # Each identity in the network needs a registration and enrollment. + fabric-ca-client register --id.name org0-orderer1 --id.secret ordererpw --id.type orderer --url https://org0-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org0-ecert-ca/rcaadmin/msp + fabric-ca-client register --id.name org0-orderer2 --id.secret ordererpw --id.type orderer --url https://org0-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org0-ecert-ca/rcaadmin/msp + fabric-ca-client register --id.name org0-orderer3 --id.secret ordererpw --id.type orderer --url https://org0-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org0-ecert-ca/rcaadmin/msp + fabric-ca-client register --id.name org0-admin --id.secret org0adminpw --id.type admin --url https://org0-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org0-ecert-ca/rcaadmin/msp --id.attrs "hf.Registrar.Roles=client,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert,abac.init=true:ecert" + + fabric-ca-client enroll --url https://org0-orderer1:ordererpw@org0-ecert-ca --csr.hosts org0-orderer1 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp + fabric-ca-client enroll --url https://org0-orderer2:ordererpw@org0-ecert-ca --csr.hosts org0-orderer2 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/msp + fabric-ca-client enroll --url https://org0-orderer3:ordererpw@org0-ecert-ca --csr.hosts org0-orderer3 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/msp + fabric-ca-client enroll --url https://org0-admin:org0adminpw@org0-ecert-ca --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/users/Admin@org0.example.com/msp + + # Each node in the network needs a TLS registration and enrollment. + fabric-ca-client register --id.name org0-orderer1 --id.secret ordererpw --id.type orderer --url https://org0-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + fabric-ca-client register --id.name org0-orderer2 --id.secret ordererpw --id.type orderer --url https://org0-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + fabric-ca-client register --id.name org0-orderer3 --id.secret ordererpw --id.type orderer --url https://org0-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + + fabric-ca-client enroll --url https://org0-orderer1:ordererpw@org0-tls-ca --csr.hosts org0-orderer1 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls + fabric-ca-client enroll --url https://org0-orderer2:ordererpw@org0-tls-ca --csr.hosts org0-orderer2 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls + fabric-ca-client enroll --url https://org0-orderer3:ordererpw@org0-tls-ca --csr.hosts org0-orderer3 --mspdir /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls + + # Copy the TLS signing keys to a fixed path for convenience when starting the orderers. + cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/tls/keystore/server.key + cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/tls/keystore/server.key + cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/tls/keystore/server.key + + # Create an MSP config.yaml (why is this not generated by the enrollment by fabric-ca-client?) + echo "NodeOUs: + Enable: true + ClientOUIdentifier: + Certificate: cacerts/org0-ecert-ca.pem + OrganizationalUnitIdentifier: client + PeerOUIdentifier: + Certificate: cacerts/org0-ecert-ca.pem + OrganizationalUnitIdentifier: peer + AdminOUIdentifier: + Certificate: cacerts/org0-ecert-ca.pem + OrganizationalUnitIdentifier: admin + OrdererOUIdentifier: + Certificate: cacerts/org0-ecert-ca.pem + OrganizationalUnitIdentifier: orderer" > /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp/config.yaml + + cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp/config.yaml /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer2.org0.example.com/msp/config.yaml + cp /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer1.org0.example.com/msp/config.yaml /var/hyperledger/fabric/organizations/ordererOrganizations/org0.example.com/orderers/org0-orderer3.org0.example.com/msp/config.yaml + ' | exec kubectl -n $NS exec deploy/org0-ecert-ca -i -- /bin/sh +} + +function create_org1_local_MSP() { + + echo 'set -x + export FABRIC_CA_CLIENT_HOME=/var/hyperledger/fabric-ca-client + export FABRIC_CA_CLIENT_TLS_CERTFILES=$FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem + + # Each identity in the network needs a registration and enrollment. + fabric-ca-client register --id.name org1-peer1 --id.secret peerpw --id.type peer --url https://org1-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org1-ecert-ca/rcaadmin/msp + fabric-ca-client register --id.name org1-peer2 --id.secret peerpw --id.type peer --url https://org1-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org1-ecert-ca/rcaadmin/msp + fabric-ca-client register --id.name org1-admin --id.secret org1adminpw --id.type admin --url https://org1-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org1-ecert-ca/rcaadmin/msp --id.attrs "hf.Registrar.Roles=client,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert,abac.init=true:ecert" + + fabric-ca-client enroll --url https://org1-peer1:peerpw@org1-ecert-ca --csr.hosts org1-peer1 --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/msp + fabric-ca-client enroll --url https://org1-peer2:peerpw@org1-ecert-ca --csr.hosts org1-peer2 --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/msp + fabric-ca-client enroll --url https://org1-admin:org1adminpw@org1-ecert-ca --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp + + # Each node in the network needs a TLS registration and enrollment. + fabric-ca-client register --id.name org1-peer1 --id.secret peerpw --id.type peer --url https://org1-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + fabric-ca-client register --id.name org1-peer2 --id.secret peerpw --id.type peer --url https://org1-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + + fabric-ca-client enroll --url https://org1-peer1:peerpw@org1-tls-ca --csr.hosts org1-peer1 --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls + fabric-ca-client enroll --url https://org1-peer2:peerpw@org1-tls-ca --csr.hosts org1-peer2 --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls + + # Copy the TLS signing keys to a fixed path for convenience when launching the peers + cp /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/keystore/server.key + cp /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/keystore/server.key + + cp /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/*_sk /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/server.key + + # Create local MSP config.yaml + echo "NodeOUs: + Enable: true + ClientOUIdentifier: + Certificate: cacerts/org1-ecert-ca.pem + OrganizationalUnitIdentifier: client + PeerOUIdentifier: + Certificate: cacerts/org1-ecert-ca.pem + OrganizationalUnitIdentifier: peer + AdminOUIdentifier: + Certificate: cacerts/org1-ecert-ca.pem + OrganizationalUnitIdentifier: admin + OrdererOUIdentifier: + Certificate: cacerts/org1-ecert-ca.pem + OrganizationalUnitIdentifier: orderer" > /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/msp/config.yaml + + + cp /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/msp/config.yaml /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/msp/config.yaml + cp /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/msp/config.yaml /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/config.yaml + ' | exec kubectl -n $NS exec deploy/org1-ecert-ca -i -- /bin/sh + +} + +function create_org2_local_MSP() { + echo 'set -x + export FABRIC_CA_CLIENT_HOME=/var/hyperledger/fabric-ca-client + export FABRIC_CA_CLIENT_TLS_CERTFILES=$FABRIC_CA_CLIENT_HOME/tls-root-cert/tls-ca-cert.pem + + # Each identity in the network needs a registration and enrollment. + fabric-ca-client register --id.name org2-peer1 --id.secret peerpw --id.type peer --url https://org2-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org2-ecert-ca/rcaadmin/msp + fabric-ca-client register --id.name org2-peer2 --id.secret peerpw --id.type peer --url https://org2-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org2-ecert-ca/rcaadmin/msp + fabric-ca-client register --id.name org2-admin --id.secret org2adminpw --id.type admin --url https://org2-ecert-ca --mspdir $FABRIC_CA_CLIENT_HOME/org2-ecert-ca/rcaadmin/msp --id.attrs "hf.Registrar.Roles=client,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert,abac.init=true:ecert" + + fabric-ca-client enroll --url https://org2-peer1:peerpw@org2-ecert-ca --csr.hosts org2-peer1 --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/msp + fabric-ca-client enroll --url https://org2-peer2:peerpw@org2-ecert-ca --csr.hosts org2-peer2 --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/msp + fabric-ca-client enroll --url https://org2-admin:org2adminpw@org2-ecert-ca --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp + + # Each node in the network needs a TLS registration and enrollment. + fabric-ca-client register --id.name org2-peer1 --id.secret peerpw --id.type peer --url https://org2-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + fabric-ca-client register --id.name org2-peer2 --id.secret peerpw --id.type peer --url https://org2-tls-ca --mspdir $FABRIC_CA_CLIENT_HOME/tls-ca/tlsadmin/msp + + fabric-ca-client enroll --url https://org2-peer1:peerpw@org2-tls-ca --csr.hosts org2-peer1 --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls + fabric-ca-client enroll --url https://org2-peer2:peerpw@org2-tls-ca --csr.hosts org2-peer2 --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls + + # Copy the TLS signing keys to a fixed path for convenience when launching the peers + cp /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/keystore/server.key + cp /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/keystore/*_sk /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/keystore/server.key + + cp /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/*_sk /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/server.key + + # Create local MSP config.yaml + echo "NodeOUs: + Enable: true + ClientOUIdentifier: + Certificate: cacerts/org2-ecert-ca.pem + OrganizationalUnitIdentifier: client + PeerOUIdentifier: + Certificate: cacerts/org2-ecert-ca.pem + OrganizationalUnitIdentifier: peer + AdminOUIdentifier: + Certificate: cacerts/org2-ecert-ca.pem + OrganizationalUnitIdentifier: admin + OrdererOUIdentifier: + Certificate: cacerts/org2-ecert-ca.pem + OrganizationalUnitIdentifier: orderer" > /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/msp/config.yaml + + cp /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/msp/config.yaml /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/msp/config.yaml + cp /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/msp/config.yaml /var/hyperledger/fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/config.yaml + ' | exec kubectl -n $NS exec deploy/org2-ecert-ca -i -- /bin/sh +} + +function create_local_MSP() { + push_fn "Creating local node MSP" + + create_org0_local_MSP + create_org1_local_MSP + create_org2_local_MSP + + pop_fn +} + +function network_up() { + + # Kube config + init_namespace + init_storage_volumes + load_org_config + + # Network TLS CAs + launch_TLS_CAs + enroll_bootstrap_TLS_CA_users + + # Network ECert CAs + register_enroll_ECert_CA_bootstrap_users + launch_ECert_CAs + enroll_bootstrap_ECert_CA_users + + # Test Network + create_local_MSP + launch_orderers + launch_peers +} + +function stop_services() { + push_fn "Stopping Fabric services" + + # These pods are busy executing `sleep MAX_INT` and do not shut down very quickly... +# kubectl -n $NS delete deployment/org0-admin-cli --grace-period=0 --force +# kubectl -n $NS delete deployment/org1-admin-cli --grace-period=0 --force +# kubectl -n $NS delete deployment/org2-admin-cli --grace-period=0 --force + + kubectl -n $NS delete deployment --all + kubectl -n $NS delete pod --all + kubectl -n $NS delete service --all + kubectl -n $NS delete configmap --all + kubectl -n $NS delete secret --all + + pop_fn +} + +function scrub_org_volumes() { + push_fn "Scrubbing Fabric volumes" + + # scrub all pv contents + kubectl -n $NS create -f kube/job-scrub-fabric-volumes.yaml + kubectl -n $NS wait --for=condition=complete --timeout=60s job/job-scrub-fabric-volumes + kubectl -n $NS delete jobs --all + + pop_fn +} + +function network_down() { + stop_services + scrub_org_volumes +} \ No newline at end of file diff --git a/test-network-k8s/scripts/utils.sh b/test-network-k8s/scripts/utils.sh new file mode 100644 index 00000000..a1631aa4 --- /dev/null +++ b/test-network-k8s/scripts/utils.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# +# Copyright IBM Corp All Rights Reserved +# +# SPDX-License-Identifier: Apache-2.0 +# + +function logging_init() { + # Reset the output and debug log files + printf '' > ${LOG_FILE} > ${DEBUG_FILE} + + # Write all output to the control flow log to STDOUT + tail -f ${LOG_FILE} & + + # Call the exit handler when we exit. + trap "exit_fn" EXIT + + # Send stdout and stderr from child programs to the debug log file + exec 1>>${DEBUG_FILE} 2>>${DEBUG_FILE} +} + +function exit_fn() { + rc=$? + + # Write an error icon to the current logging statement. + if [ "0" -ne $rc ]; then + pop_fn $rc + fi + + # always remove the log trailer when the process exits. + pkill -P $$ +} + +function push_fn() { + #echo -ne " - entering ${FUNCNAME[1]} with arguments $@" + + echo -ne " - $@ ..." >> ${LOG_FILE} +} + +function log() { + echo -e $@ >> ${LOG_FILE} +} + +function pop_fn() { +# echo exiting ${FUNCNAME[1]} + + local res=$1 + if [ $# -eq 0 ]; then + echo -ne "\r✅" >> ${LOG_FILE} + + elif [ $res -eq 0 ]; then + echo -ne "\r✅" >> ${LOG_FILE} + + elif [ $res -eq 1 ]; then + echo -ne "\r⚠️" >> ${LOG_FILE} + + elif [ $res -eq 2 ]; then + echo -ne "\r☠️" >> ${LOG_FILE} + + else + echo -ne "\r" >> ${LOG_FILE} + fi + + echo "" >> ${LOG_FILE} +} + From 576b2e74c963d8dfcfb04a7a199078d0e24256c6 Mon Sep 17 00:00:00 2001 From: jkneubuh <86427252+jkneubuh@users.noreply.github.com> Date: Thu, 7 Oct 2021 14:08:22 -0400 Subject: [PATCH 013/106] Do not weep for the KIND prototype. The [new one](test-network-k8s) is much better. (#503) "Farewell! thou art too dear for my possessing, And like enough thou knowst thy estimate. The Charter of thy worth gives thee releasing; My bonds in thee are all determinate. For how do I hold thee but by thy granting, And for that riches where is my deserving? The cause of this fair gift in me is wanting, And so my patent back again is swerving. Thy self thou gav'st, thy own worth then not knowing, Or me, to whom thou gav'st it, else mistaking, So thy great gift, upon misprision growing, Comes home again, on better judgement making. Thus have I had thee as a dream doth flatter: In sleep a king, but waking no such matter." - bill Signed-off-by: Josh Kneubuhl --- README.md | 7 + test-network-kind/.gitignore | 2 - test-network-kind/README.md | 269 ------- test-network-kind/bin/make-kind-with-reg.sh | 31 - .../chaincode/asset-transfer-basic-debug.tgz | Bin 416 -> 0 bytes .../asset-transfer-basic-debug/code.tar.gz | Bin 196 -> 0 bytes .../connection.json | 5 - .../asset-transfer-basic-debug/metadata.json | 4 - .../chaincode/asset-transfer-basic.tgz | Bin 411 -> 0 bytes .../asset-transfer-basic/code.tar.gz | Bin 195 -> 0 bytes .../asset-transfer-basic/connection.json | 5 - .../asset-transfer-basic/metadata.json | 4 - test-network-kind/config/configtx.yaml | 389 --------- test-network-kind/config/core.yaml | 759 ------------------ test-network-kind/config/crypto-config.yaml | 59 -- test-network-kind/config/orderer.yaml | 420 ---------- .../kube/cc-asset-transfer-basic.yaml | 46 -- test-network-kind/kube/debug.yaml | 55 -- .../kube/job-create-channel-config.yaml | 45 -- test-network-kind/kube/job-crypto-config.yaml | 41 - .../kube/job-orderer-genesis.yaml | 44 - .../kube/job-scrub-fabric-volume.yaml | 32 - .../kube/job-update-org1-anchor-peers.yaml | 45 -- .../kube/job-update-org2-anchor-peers.yaml | 45 -- test-network-kind/kube/ns-test-network.yaml | 10 - test-network-kind/kube/orderer1.yaml | 87 -- test-network-kind/kube/orderer2.yaml | 87 -- test-network-kind/kube/orderer3.yaml | 87 -- test-network-kind/kube/org1-peer1.yaml | 110 --- test-network-kind/kube/org1-peer2.yaml | 105 --- test-network-kind/kube/org2-peer1.yaml | 105 --- test-network-kind/kube/org2-peer2.yaml | 105 --- test-network-kind/kube/pv-fabric.yaml | 18 - test-network-kind/kube/pvc-fabric.yaml | 17 - 34 files changed, 7 insertions(+), 3031 deletions(-) delete mode 100644 test-network-kind/.gitignore delete mode 100644 test-network-kind/README.md delete mode 100755 test-network-kind/bin/make-kind-with-reg.sh delete mode 100644 test-network-kind/chaincode/asset-transfer-basic-debug.tgz delete mode 100644 test-network-kind/chaincode/asset-transfer-basic-debug/code.tar.gz delete mode 100644 test-network-kind/chaincode/asset-transfer-basic-debug/connection.json delete mode 100644 test-network-kind/chaincode/asset-transfer-basic-debug/metadata.json delete mode 100644 test-network-kind/chaincode/asset-transfer-basic.tgz delete mode 100644 test-network-kind/chaincode/asset-transfer-basic/code.tar.gz delete mode 100644 test-network-kind/chaincode/asset-transfer-basic/connection.json delete mode 100644 test-network-kind/chaincode/asset-transfer-basic/metadata.json delete mode 100644 test-network-kind/config/configtx.yaml delete mode 100644 test-network-kind/config/core.yaml delete mode 100644 test-network-kind/config/crypto-config.yaml delete mode 100644 test-network-kind/config/orderer.yaml delete mode 100644 test-network-kind/kube/cc-asset-transfer-basic.yaml delete mode 100644 test-network-kind/kube/debug.yaml delete mode 100644 test-network-kind/kube/job-create-channel-config.yaml delete mode 100644 test-network-kind/kube/job-crypto-config.yaml delete mode 100644 test-network-kind/kube/job-orderer-genesis.yaml delete mode 100644 test-network-kind/kube/job-scrub-fabric-volume.yaml delete mode 100644 test-network-kind/kube/job-update-org1-anchor-peers.yaml delete mode 100644 test-network-kind/kube/job-update-org2-anchor-peers.yaml delete mode 100644 test-network-kind/kube/ns-test-network.yaml delete mode 100644 test-network-kind/kube/orderer1.yaml delete mode 100644 test-network-kind/kube/orderer2.yaml delete mode 100644 test-network-kind/kube/orderer3.yaml delete mode 100644 test-network-kind/kube/org1-peer1.yaml delete mode 100644 test-network-kind/kube/org1-peer2.yaml delete mode 100644 test-network-kind/kube/org2-peer1.yaml delete mode 100644 test-network-kind/kube/org2-peer2.yaml delete mode 100644 test-network-kind/kube/pv-fabric.yaml delete mode 100644 test-network-kind/kube/pvc-fabric.yaml diff --git a/README.md b/README.md index 476650dc..1b5ba6c6 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,13 @@ Organization peers and an ordering service node. You can use it on your local ma You can also use it to deploy and test your own Fabric chaincodes and applications. To get started, see the [test network tutorial](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html). +The [Kubernetes Test Network](test-network-k8s) sample builds upon the Compose network, constructing a Fabric +network with peer, orderer, and CA infrastructure nodes running on Kubernetes. In addition to providing a sample +Kubernetes guide, the Kube test network can be used as a platform to author and debug _cloud ready_ Fabric Client +applications on a development or CI workstation. + + + ## Asset transfer samples and tutorials The asset transfer series provides a series of sample smart contracts and applications to demonstrate how to store and transfer assets using Hyperledger Fabric. diff --git a/test-network-kind/.gitignore b/test-network-kind/.gitignore deleted file mode 100644 index ddef5d2a..00000000 --- a/test-network-kind/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -crypto-config/ -channel-artifacts/ diff --git a/test-network-kind/README.md b/test-network-kind/README.md deleted file mode 100644 index 260c0f41..00000000 --- a/test-network-kind/README.md +++ /dev/null @@ -1,269 +0,0 @@ - -# Kubernetes Test Network - -This directory includes a set of kubernetes deployment manifests, scripts, and configuration files suitable -for running the Hyperledger Fabric test network on a local [KIND](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) -cluster. - -This is currently an experimental branch. No attempt has been made to optimize or streamline the actual -deployment to kubernetes - no helm charts, operators, kustomization overlays, etc. are involved at this -early genesis. This is merely a set of kube manifests suitable for replicating the test network on -Kubernetes. - - -## Areas for Improvement - -- [ ] Introduce `fabctl` as a bridge between objectives running locally and activities running remotely (`network.sh` equivalent, e.g. see [fabric-hyper-kube](https://github.com/hyperledgendary/fabric-hyper-kube)) -- [ ] Provide simple scripts or CLI driver routines (e.g. `network.sh up` -> `kubectl apply ...`) -- [ ] `cryptogen` -> Configure a CA -- [ ] couchdb state database -- [ ] KIND is only one path to a Kube. Check that we are also in good shape with minikube, IBM Fyre, IKS, aws, OCP, azure, etc. -- [ ] Use kustomize, ~helm~, operator, etc. etc. to properly integrate and install. -- [ ] The manifests directly pull 2.3.2 fabric images and have an imagePullPolicy: Always. Find a better technique to pull :latest tag from docker hub or the kind control plane. -- [ ] The fabric config files (2.3.2) are also hard-wired into the /config folder. It would be nice if this project could use the fab release archive (or better - directly from git), and override the stanzas in core.yaml (e.g. externalBuilder) -- [ ] Publish [fabric-ccs-builder](https://github.com/hyperledgendary/fabric-ccs-builder) image to docker hub -- [ ] Publish [asset-transfer-basic](../asset-transfer-basic/chaincode-external) and external chaincode sample images to docker hub. -- [ ] The peer deployments currently mount the chaincode application bundle into a volume at launch time. This is wrong - chaincode bundles must come AFTER the peers have been deployed, and should not force a peer pod restart. -- [ ] Pick out the CC_PACKAGE_ID from `peer chaincode install` and load into a configmap / k8s secret / env -- [ ] Configure multiple pvc - one per network node, rather than one shared volume for all network elements. -- [ ] Configure the Fabric REST sample - needs attention in configuring connection profiles, pems, CAs, and signing keys. - -## Prerequisites - -- [Docker](https://www.docker.com) -- [kubectl](https://kubernetes.io/docs/tasks/tools/) -- [KIND](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) -- [fabric-ccs-builder](#fabric-ccs-builder) docker image - -### Fabric CCS Builder - -Smart contracts running on Kubernetes rely extensively on the [Chaincode as a Service](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html) -deployment pattern. This test network uses the [fabric-ccs-builder](https://github.com/jkneubuh/fabric-ccs-builder/tree/feature/docker-bundle) -image `release`, `build`, and `detect` binaries, copied into the peer pods via an init container at -deployment time. Before starting the test network, build the ccs image locally and push to the KIND control plane: - -```shell -git clone https://github.com/hyperledgendary/fabric-ccs-builder.git /tmp/fabric-ccs-builder - -docker build -t hyperledgendary/fabric-ccs-builder /tmp/fabric-ccs-builder -``` - -## Test Network - -### Kube - -Create a Kubernetes cluster and [load docker images](https://kind.sigs.k8s.io/docs/user/quick-start/#loading-an-image-into-your-cluster) into the KIND control plane. -```shell -kind create cluster - -kind load docker-image hyperledgendary/fabric-ccs-builder -``` - -Create a dedicated namespace and persistent volume for the test-network: -```shell -kubectl create -f kube/pv-fabric.yaml -kubectl create -f kube/ns-test-network.yaml -kubectl -n test-network create -f kube/pvc-fabric.yaml -``` - -### Network Config - -```shell -kubectl -n test-network create configmap fabric-config --from-file=config/ -kubectl -n test-network create configmap chaincode-config --from-file=chaincode/ -``` - -### Channel Artifacts - -```shell -kubectl -n test-network create -f kube/debug.yaml -kubectl -n test-network create -f kube/job-crypto-config.yaml -kubectl -n test-network create -f kube/job-orderer-genesis.yaml -kubectl -n test-network create -f kube/job-create-channel-config.yaml -kubectl -n test-network create -f kube/job-update-org1-anchor-peers.yaml -kubectl -n test-network create -f kube/job-update-org2-anchor-peers.yaml -``` -(Wait for these jobs to complete. It can take a few seconds for images to be pulled from docker hub.) - -### Orderers -```shell -kubectl -n test-network apply -f kube/orderer1.yaml -kubectl -n test-network apply -f kube/orderer2.yaml -kubectl -n test-network apply -f kube/orderer3.yaml -``` - -### Peers -```shell -kubectl -n test-network apply -f kube/org1-peer1.yaml -kubectl -n test-network apply -f kube/org1-peer2.yaml -kubectl -n test-network apply -f kube/org2-peer1.yaml -kubectl -n test-network apply -f kube/org2-peer2.yaml -``` - -### Create `mychannel` - -```shell -kubectl -n test-network exec deploy/org1-peer1 -i -t -- /bin/sh - -export CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp - -peer channel \ - create \ - -c mychannel \ - -o orderer1:6050 \ - -f /var/hyperledger/fabric/channel-artifacts/mychannel.tx \ - --outputBlock /var/hyperledger/fabric/channel-artifacts/mychannel.block \ - --tls \ - --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/ca.crt - -peer channel \ - update \ - -o orderer1:6050 \ - -c mychannel \ - -f /var/hyperledger/fabric/channel-artifacts/Org1MSPanchors.tx \ - --tls \ - --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/ca.crt - -exit -``` - -### Join Peers - -```shell -kubectl \ - -n test-network \ - exec deploy/org1-peer1 \ - -i -t -- \ - /bin/sh -c 'CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp peer channel join -b /var/hyperledger/fabric/channel-artifacts/mychannel.block' -``` -```shell -kubectl \ - -n test-network \ - exec deploy/org1-peer2 \ - -i -t -- \ - /bin/sh -c 'CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp peer channel join -b /var/hyperledger/fabric/channel-artifacts/mychannel.block' -``` - -```shell -kubectl \ - -n test-network \ - exec deploy/org2-peer1 \ - -i -t -- \ - /bin/sh -c 'CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp peer channel join -b /var/hyperledger/fabric/channel-artifacts/mychannel.block' -``` - -```shell -kubectl \ - -n test-network \ - exec deploy/org2-peer2 \ - -i -t -- \ - /bin/sh -c 'CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp peer channel join -b /var/hyperledger/fabric/channel-artifacts/mychannel.block' -``` - -## Chaincode - -### Install - -```shell -kubectl -n test-network exec deploy/org1-peer1 -i -t -- /bin/sh -export CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp - -peer lifecycle \ - chaincode install \ - /var/hyperledger/fabric/chaincode/asset-transfer-basic.tgz - -exit -``` - -### Launch External Chaincode - -- [ ] Determine `CHAINCODE_ID` from install command and load as a config map / env entry in the cc deployment spec. -- [ ] Use an [insecure docker registry](bin/make-kind-with-reg.sh) to build and deploy chaincode images without Docker hub or the kind control plane. - -```shell -docker build \ - -t hyperledger/asset-transfer-basic \ - ../asset-transfer-basic/chaincode-external - -kind load docker-image hyperledger/asset-transfer-basic -``` - -```shell -kubectl -n test-network apply -f kube/cc-asset-transfer-basic.yaml -``` - -### Approve and Commit - -```shell -kubectl -n test-network exec deploy/org1-peer1 -i -t -- /bin/sh -export FABRIC_LOGGING_SPEC=INFO -export CORE_PEER_MSPCONFIGPATH=/var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp -export CC_PACKAGE_ID=basic_1.0:d730a5ce916e120f2a2509ee33527a0df68cadac678f5eb196737ad10ba42da9 - -peer lifecycle \ - chaincode approveformyorg \ - -o orderer1:6050 \ - --channelID mychannel \ - --name basic \ - --version 1 \ - --package-id $CC_PACKAGE_ID \ - --sequence 1 \ - --tls \ - --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/msp/tlscacerts/tlsca.example.com-cert.pem - -peer lifecycle \ - chaincode commit \ - -o orderer1:6050 \ - --channelID mychannel \ - --name basic \ - --version 1 \ - --sequence 1 \ - --tls \ - --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -``` - -### Query - -(run on org1-peer1) -```shell -peer chaincode \ - invoke \ - -o orderer1:6050 \ - -C mychannel \ - -n basic \ - -c '{"Args":["CreateAsset","1","blue","35","tom","1000"]}' \ - --tls \ - --cafile /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/ca.crt \ - -sleep 2 - -peer chaincode \ - query \ - -C mychannel \ - -n basic \ - -c '{"Args":["ReadAsset","1"]}' - -exit -``` - -### Reset Network - -```shell -kubectl -n test-network delete deployment --all -kubectl -n test-network delete pod --all -kubectl -n test-network delete service --all -kubectl -n test-network delete configmap --all -kubectl -n test-network delete secret --all -kubectl -n test-network create -f kube/job-scrub-fabric-volume.yaml -kubectl -n test-network wait --for=condition=complete --timeout=60s job/job-scrub-fabric-volume -kubectl -n test-network delete job --all -``` -[GOTO Config](#network-config) - -or ... -```shell -kind delete cluster -``` -[GOTO Kube](#kube) - - diff --git a/test-network-kind/bin/make-kind-with-reg.sh b/test-network-kind/bin/make-kind-with-reg.sh deleted file mode 100755 index 7967f049..00000000 --- a/test-network-kind/bin/make-kind-with-reg.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -set -o errexit - -# create registry container unless it already exists -reg_name='kind-registry' -reg_port='5000' -running="$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" -if [ "${running}" != 'true' ]; then - docker run \ - -d --restart=always -p "${reg_port}:5000" --name "${reg_name}" \ - registry:2 -fi - -# create a cluster with the local registry enabled in containerd -cat <i#U+VFK&ND7=cSe=m1f{l2UM1phQ}O; zPZZ$v5CPR(3JOXkl?ACvRtid~6(y-fd5JknIv~-U#H7?5kZ@9Bab|LSN@`MRdc2{Y zff85kK)ZSrPzxmIr=;oubAVoY70v7*l>dzlOyK$7+ytEe4Gl)~KV5))HwVMBrBaCu z%x}-1=4v(&U=6rl=Xzq7N09u&e?3dmj%3WbU=z0V|GgC#To1lmB2r{F-C(-GW$CpG zzh8QhROFWKuFzr<+Bz-8cdwdd{(Dhf$wi{QOJ`l2q~w%+D5LF!;_VuabH&o(Gt+n< zN*&u9w}$ud^!jbV7p(suQFiAjR@AX*k8W{)T%+h?->kdjTY_o$Th&9$mujkn&z){= za8SS0>yFunQ>9|>9HRsZ4GNwr)IZyAr|&sQ<>p7G+fT}M7&rzx1V_Or7zLwXXaWER KuR2fw3;+PCTEQCt diff --git a/test-network-kind/chaincode/asset-transfer-basic-debug/code.tar.gz b/test-network-kind/chaincode/asset-transfer-basic-debug/code.tar.gz deleted file mode 100644 index 917183e3ea65e2c527e66b53682a91dc4ad46144..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196 zcmV;#06YI5iwFSbr5a%X1MSbt3WG2Z1yI+1Maa5HQXirIjHG77XqwPGR;B;msL(~h z?xYlQHkUA$Fw+~Yq4(10Vsb`jM<9eWRfU#hO}!>LZ|@Z?8KM=9rJB)_B0_7zXokok z+k6Pla~oHgW)0yQ#=Tyw4a1jzwo}kM|HLCl2y-DUIEPz=N8@}UOh1Dyr1oGnSM4Rj yr==+*SDlwPFu^Z%O58T^%5@g*L0S-TFmUA{f9AhFFG-Rl+3^C~YpR5_6PvK%zN`NvSy?;iSak%;b1OJp(1K+JScO zD4;G#&QD3z1Lgp|^eUR!K`8$l8yLg#zpflK<-?Pl(r%LH*lM5q&;R8V zeZT%^dSt8Z>-jrUd!9OJcDqy_F4E+7Y*|+jCh_W`*jxqO*~t^~lQ&;V%9*?G!IRjU zgN@S;^j?YDQR7;27ut90j9b6pVr)3IKg48gT#& F006&U#9jaZ diff --git a/test-network-kind/chaincode/asset-transfer-basic/code.tar.gz b/test-network-kind/chaincode/asset-transfer-basic/code.tar.gz deleted file mode 100644 index b97295ec651b611441110513b23591fb282734e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmV;!06hO6iwFQqb^u`j1MSbj3c@f924K&7in6nlRJMtGnbEZwcFqo)_9VW$?FJr1 zy$uoiK?&tgOCl#@P&z%C-9VGstN{S(vShIy>T0gAU+yzrau!aEq2`007$)T3rAD diff --git a/test-network-kind/chaincode/asset-transfer-basic/connection.json b/test-network-kind/chaincode/asset-transfer-basic/connection.json deleted file mode 100644 index 1e210c05..00000000 --- a/test-network-kind/chaincode/asset-transfer-basic/connection.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "address": "cc-asset-transfer-basic:9999", - "dial_timeout": "10s", - "tls_required": false -} \ No newline at end of file diff --git a/test-network-kind/chaincode/asset-transfer-basic/metadata.json b/test-network-kind/chaincode/asset-transfer-basic/metadata.json deleted file mode 100644 index bb7056c0..00000000 --- a/test-network-kind/chaincode/asset-transfer-basic/metadata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "external", - "label": "basic_1.0" -} \ No newline at end of file diff --git a/test-network-kind/config/configtx.yaml b/test-network-kind/config/configtx.yaml deleted file mode 100644 index ab11cce4..00000000 --- a/test-network-kind/config/configtx.yaml +++ /dev/null @@ -1,389 +0,0 @@ -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -################################################################################ -# -# Section: Organizations -# -# - This section defines the different organizational identities which will -# be referenced later in the configuration. -# -################################################################################ -Organizations: - - # SampleOrg defines an MSP using the sampleconfig. It should never be used - # in production but may be used as a template for other definitions - - &OrdererOrg - # DefaultOrg defines the organization which is used in the sampleconfig - # of the fabric.git development environment - Name: OrdererOrg - - # ID to load the MSP definition as - ID: OrdererMSP - - # MSPDir is the filesystem path which contains the MSP configuration - MSPDir: crypto-config/ordererOrganizations/example.com/msp - - # Policies defines the set of policies at this level of the config tree - # For organization policies, their canonical path is usually - # /Channel/// - Policies: - Readers: - Type: Signature - Rule: "OR('OrdererMSP.member')" - Writers: - Type: Signature - Rule: "OR('OrdererMSP.member')" - Admins: - Type: Signature - Rule: "OR('OrdererMSP.admin')" - - OrdererEndpoints: - - orderer1:6050 - - orderer2:6050 - - orderer3:6050 - - - &Org1 - # DefaultOrg defines the organization which is used in the sampleconfig - # of the fabric.git development environment - Name: Org1MSP - - # ID to load the MSP definition as - ID: Org1MSP - - MSPDir: crypto-config/peerOrganizations/org1.example.com/msp - - # Policies defines the set of policies at this level of the config tree - # For organization policies, their canonical path is usually - # /Channel/// - Policies: - Readers: - Type: Signature - Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')" - Writers: - Type: Signature - Rule: "OR('Org1MSP.admin', 'Org1MSP.client')" - Admins: - Type: Signature - Rule: "OR('Org1MSP.admin')" - Endorsement: - Type: Signature - Rule: "OR('Org1MSP.peer')" - - # leave this flag set to true. - AnchorPeers: - # AnchorPeers defines the location of peers which can be used - # for cross org gossip communication. Note, this value is only - # encoded in the genesis block in the Application section context - - Host: org1-peer1 - Port: 7051 - - - &Org2 - # DefaultOrg defines the organization which is used in the sampleconfig - # of the fabric.git development environment - Name: Org2MSP - - # ID to load the MSP definition as - ID: Org2MSP - - MSPDir: crypto-config/peerOrganizations/org2.example.com/msp - - # Policies defines the set of policies at this level of the config tree - # For organization policies, their canonical path is usually - # /Channel/// - Policies: - Readers: - Type: Signature - Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')" - Writers: - Type: Signature - Rule: "OR('Org2MSP.admin', 'Org2MSP.client')" - Admins: - Type: Signature - Rule: "OR('Org2MSP.admin')" - Endorsement: - Type: Signature - Rule: "OR('Org2MSP.peer')" - - AnchorPeers: - # AnchorPeers defines the location of peers which can be used - # for cross org gossip communication. Note, this value is only - # encoded in the genesis block in the Application section context - - Host: org2-peer1 - Port: 7051 - -################################################################################ -# -# SECTION: Capabilities -# -# - This section defines the capabilities of fabric network. This is a new -# concept as of v1.1.0 and should not be utilized in mixed networks with -# v1.0.x peers and orderers. Capabilities define features which must be -# present in a fabric binary for that binary to safely participate in the -# fabric network. For instance, if a new MSP type is added, newer binaries -# might recognize and validate the signatures from this type, while older -# binaries without this support would be unable to validate those -# transactions. This could lead to different versions of the fabric binaries -# having different world states. Instead, defining a capability for a channel -# informs those binaries without this capability that they must cease -# processing transactions until they have been upgraded. For v1.0.x if any -# capabilities are defined (including a map with all capabilities turned off) -# then the v1.0.x peer will deliberately crash. -# -################################################################################ -Capabilities: - # Channel capabilities apply to both the orderers and the peers and must be - # supported by both. - # Set the value of the capability to true to require it. - Channel: &ChannelCapabilities - # V2_0 capability ensures that orderers and peers behave according - # to v2.0 channel capabilities. Orderers and peers from - # prior releases would behave in an incompatible way, and are therefore - # not able to participate in channels at v2.0 capability. - # Prior to enabling V2.0 channel capabilities, ensure that all - # orderers and peers on a channel are at v2.0.0 or later. - V2_0: true - - # Orderer capabilities apply only to the orderers, and may be safely - # used with prior release peers. - # Set the value of the capability to true to require it. - Orderer: &OrdererCapabilities - # V2_0 orderer capability ensures that orderers behave according - # to v2.0 orderer capabilities. Orderers from - # prior releases would behave in an incompatible way, and are therefore - # not able to participate in channels at v2.0 orderer capability. - # Prior to enabling V2.0 orderer capabilities, ensure that all - # orderers on channel are at v2.0.0 or later. - V2_0: true - - # Application capabilities apply only to the peer network, and may be safely - # used with prior release orderers. - # Set the value of the capability to true to require it. - Application: &ApplicationCapabilities - # V2_0 application capability ensures that peers behave according - # to v2.0 application capabilities. Peers from - # prior releases would behave in an incompatible way, and are therefore - # not able to participate in channels at v2.0 application capability. - # Prior to enabling V2.0 application capabilities, ensure that all - # peers on channel are at v2.0.0 or later. - V2_0: true - -################################################################################ -# -# SECTION: Application -# -# - This section defines the values to encode into a config transaction or -# genesis block for application related parameters -# -################################################################################ -Application: &ApplicationDefaults - - # Organizations is the list of orgs which are defined as participants on - # the application side of the network - Organizations: - - # Policies defines the set of policies at this level of the config tree - # For Application policies, their canonical path is - # /Channel/Application/ - Policies: - Readers: - Type: ImplicitMeta - Rule: "ANY Readers" - Writers: - Type: ImplicitMeta - Rule: "ANY Writers" - Admins: - Type: ImplicitMeta - Rule: "MAJORITY Admins" - LifecycleEndorsement: - Type: Signature - Rule: "OR('Org1MSP.peer','Org2MSP.peer')" - Endorsement: - Type: Signature - Rule: "OR('Org1MSP.peer','Org2MSP.peer')" - - Capabilities: - <<: *ApplicationCapabilities -################################################################################ -# -# SECTION: Orderer -# -# - This section defines the values to encode into a config transaction or -# genesis block for orderer related parameters -# -################################################################################ -Orderer: &OrdererDefaults - - # Orderer Type: The orderer implementation to start - OrdererType: etcdraft - - EtcdRaft: - Consenters: - - Host: orderer1 - Port: 6050 - ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt - ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt - - Host: orderer2 - Port: 6050 - ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt - ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt - - Host: orderer3 - Port: 6050 - ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/server.crt - ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/server.crt - - # Options to be specified for all the etcd/raft nodes. The values here - # are the defaults for all new channels and can be modified on a - # per-channel basis via configuration updates. - Options: - # TickInterval is the time interval between two Node.Tick invocations. - #TickInterval: 500ms default - TickInterval: 2500ms - - # ElectionTick is the number of Node.Tick invocations that must pass - # between elections. That is, if a follower does not receive any - # message from the leader of current term before ElectionTick has - # elapsed, it will become candidate and start an election. - # ElectionTick must be greater than HeartbeatTick. - # ElectionTick: 10 default - ElectionTick: 5 - - # HeartbeatTick is the number of Node.Tick invocations that must - # pass between heartbeats. That is, a leader sends heartbeat - # messages to maintain its leadership every HeartbeatTick ticks. - HeartbeatTick: 1 - - # MaxInflightBlocks limits the max number of in-flight append messages - # during optimistic replication phase. - MaxInflightBlocks: 5 - - # SnapshotIntervalSize defines number of bytes per which a snapshot is taken - SnapshotIntervalSize: 16 MB - - # Batch Timeout: The amount of time to wait before creating a batch - BatchTimeout: 2s - - # Batch Size: Controls the number of messages batched into a block - BatchSize: - - # Max Message Count: The maximum number of messages to permit in a batch - MaxMessageCount: 10 - - # Absolute Max Bytes: The absolute maximum number of bytes allowed for - # the serialized messages in a batch. - AbsoluteMaxBytes: 99 MB - - # Preferred Max Bytes: The preferred maximum number of bytes allowed for - # the serialized messages in a batch. A message larger than the preferred - # max bytes will result in a batch larger than preferred max bytes. - PreferredMaxBytes: 512 KB - - # Organizations is the list of orgs which are defined as participants on - # the orderer side of the network - Organizations: - - # Policies defines the set of policies at this level of the config tree - # For Orderer policies, their canonical path is - # /Channel/Orderer/ - Policies: - Readers: - Type: ImplicitMeta - Rule: "ANY Readers" - Writers: - Type: ImplicitMeta - Rule: "ANY Writers" - Admins: - Type: ImplicitMeta - Rule: "MAJORITY Admins" - # BlockValidation specifies what signatures must be included in the block - # from the orderer for the peer to validate it. - BlockValidation: - Type: ImplicitMeta - Rule: "ANY Writers" - -################################################################################ -# -# CHANNEL -# -# This section defines the values to encode into a config transaction or -# genesis block for channel related parameters. -# -################################################################################ -Channel: &ChannelDefaults - # Policies defines the set of policies at this level of the config tree - # For Channel policies, their canonical path is - # /Channel/ - Policies: - # Who may invoke the 'Deliver' API - Readers: - Type: ImplicitMeta - Rule: "ANY Readers" - # Who may invoke the 'Broadcast' API - Writers: - Type: ImplicitMeta - Rule: "ANY Writers" - # By default, who may modify elements at this config level - Admins: - Type: ImplicitMeta - Rule: "MAJORITY Admins" - - # Capabilities describes the channel level capabilities, see the - # dedicated Capabilities section elsewhere in this file for a full - # description - Capabilities: - <<: *ChannelCapabilities - -################################################################################ -# -# Profile -# -# - Different configuration profiles may be encoded here to be specified -# as parameters to the configtxgen tool -# -################################################################################ -Profiles: - - TwoOrgsOrdererGenesis: - <<: *ChannelDefaults - Orderer: - <<: *OrdererDefaults - Organizations: - - *OrdererOrg - Capabilities: - <<: *OrdererCapabilities - Consortiums: - SampleConsortium: - Organizations: - - *Org1 - - *Org2 - TwoOrgsChannel: - Consortium: SampleConsortium - <<: *ChannelDefaults - Application: - <<: *ApplicationDefaults - Organizations: - - *Org1 - - *Org2 - Capabilities: - <<: *ApplicationCapabilities - Org1Channel: - Consortium: SampleConsortium - <<: *ChannelDefaults - Application: - <<: *ApplicationDefaults - Organizations: - - *Org1 - Capabilities: - <<: *ApplicationCapabilities - Org2Channel: - Consortium: SampleConsortium - <<: *ChannelDefaults - Application: - <<: *ApplicationDefaults - Organizations: - - *Org2 - Capabilities: - <<: *ApplicationCapabilities diff --git a/test-network-kind/config/core.yaml b/test-network-kind/config/core.yaml deleted file mode 100644 index 0b4738d7..00000000 --- a/test-network-kind/config/core.yaml +++ /dev/null @@ -1,759 +0,0 @@ -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# - -############################################################################### -# -# Peer section -# -############################################################################### -peer: - - # The peer id provides a name for this peer instance and is used when - # naming docker resources. - id: jdoe - - # The networkId allows for logical separation of networks and is used when - # naming docker resources. - networkId: dev - - # The Address at local network interface this Peer will listen on. - # By default, it will listen on all network interfaces - listenAddress: 0.0.0.0:7051 - - # The endpoint this peer uses to listen for inbound chaincode connections. - # If this is commented-out, the listen address is selected to be - # the peer's address (see below) with port 7052 - # chaincodeListenAddress: 0.0.0.0:7052 - - # The endpoint the chaincode for this peer uses to connect to the peer. - # If this is not specified, the chaincodeListenAddress address is selected. - # And if chaincodeListenAddress is not specified, address is selected from - # peer address (see below). If specified peer address is invalid then it - # will fallback to the auto detected IP (local IP) regardless of the peer - # addressAutoDetect value. - # chaincodeAddress: 0.0.0.0:7052 - - # When used as peer config, this represents the endpoint to other peers - # in the same organization. For peers in other organization, see - # gossip.externalEndpoint for more info. - # When used as CLI config, this means the peer's endpoint to interact with - address: 0.0.0.0:7051 - - # Whether the Peer should programmatically determine its address - # This case is useful for docker containers. - # When set to true, will override peer address. - addressAutoDetect: false - - # Keepalive settings for peer server and clients - keepalive: - # Interval is the duration after which if the server does not see - # any activity from the client it pings the client to see if it's alive - interval: 7200s - # Timeout is the duration the server waits for a response - # from the client after sending a ping before closing the connection - timeout: 20s - # MinInterval is the minimum permitted time between client pings. - # If clients send pings more frequently, the peer server will - # disconnect them - minInterval: 60s - # Client keepalive settings for communicating with other peer nodes - client: - # Interval is the time between pings to peer nodes. This must - # greater than or equal to the minInterval specified by peer - # nodes - interval: 60s - # Timeout is the duration the client waits for a response from - # peer nodes before closing the connection - timeout: 20s - # DeliveryClient keepalive settings for communication with ordering - # nodes. - deliveryClient: - # Interval is the time between pings to ordering nodes. This must - # greater than or equal to the minInterval specified by ordering - # nodes. - interval: 60s - # Timeout is the duration the client waits for a response from - # ordering nodes before closing the connection - timeout: 20s - - - # Gossip related configuration - gossip: - # Bootstrap set to initialize gossip with. - # This is a list of other peers that this peer reaches out to at startup. - # Important: The endpoints here have to be endpoints of peers in the same - # organization, because the peer would refuse connecting to these endpoints - # unless they are in the same organization as the peer. - bootstrap: 127.0.0.1:7051 - - # NOTE: orgLeader and useLeaderElection parameters are mutual exclusive. - # Setting both to true would result in the termination of the peer - # since this is undefined state. If the peers are configured with - # useLeaderElection=false, make sure there is at least 1 peer in the - # organization that its orgLeader is set to true. - - # Defines whenever peer will initialize dynamic algorithm for - # "leader" selection, where leader is the peer to establish - # connection with ordering service and use delivery protocol - # to pull ledger blocks from ordering service. - useLeaderElection: false - # Statically defines peer to be an organization "leader", - # where this means that current peer will maintain connection - # with ordering service and disseminate block across peers in - # its own organization. Multiple peers or all peers in an organization - # may be configured as org leaders, so that they all pull - # blocks directly from ordering service. - orgLeader: true - - # Interval for membershipTracker polling - membershipTrackerInterval: 5s - - # Overrides the endpoint that the peer publishes to peers - # in its organization. For peers in foreign organizations - # see 'externalEndpoint' - endpoint: - # Maximum count of blocks stored in memory - maxBlockCountToStore: 10 - # Max time between consecutive message pushes(unit: millisecond) - maxPropagationBurstLatency: 10ms - # Max number of messages stored until a push is triggered to remote peers - maxPropagationBurstSize: 10 - # Number of times a message is pushed to remote peers - propagateIterations: 1 - # Number of peers selected to push messages to - propagatePeerNum: 3 - # Determines frequency of pull phases(unit: second) - # Must be greater than digestWaitTime + responseWaitTime - pullInterval: 4s - # Number of peers to pull from - pullPeerNum: 3 - # Determines frequency of pulling state info messages from peers(unit: second) - requestStateInfoInterval: 4s - # Determines frequency of pushing state info messages to peers(unit: second) - publishStateInfoInterval: 4s - # Maximum time a stateInfo message is kept until expired - stateInfoRetentionInterval: - # Time from startup certificates are included in Alive messages(unit: second) - publishCertPeriod: 10s - # Should we skip verifying block messages or not (currently not in use) - skipBlockVerification: false - # Dial timeout(unit: second) - dialTimeout: 3s - # Connection timeout(unit: second) - connTimeout: 2s - # Buffer size of received messages - recvBuffSize: 20 - # Buffer size of sending messages - sendBuffSize: 200 - # Time to wait before pull engine processes incoming digests (unit: second) - # Should be slightly smaller than requestWaitTime - digestWaitTime: 1s - # Time to wait before pull engine removes incoming nonce (unit: milliseconds) - # Should be slightly bigger than digestWaitTime - requestWaitTime: 1500ms - # Time to wait before pull engine ends pull (unit: second) - responseWaitTime: 2s - # Alive check interval(unit: second) - aliveTimeInterval: 5s - # Alive expiration timeout(unit: second) - aliveExpirationTimeout: 25s - # Reconnect interval(unit: second) - reconnectInterval: 25s - # Max number of attempts to connect to a peer - maxConnectionAttempts: 120 - # Message expiration factor for alive messages - msgExpirationFactor: 20 - # This is an endpoint that is published to peers outside of the organization. - # If this isn't set, the peer will not be known to other organizations. - externalEndpoint: - # Leader election service configuration - election: - # Longest time peer waits for stable membership during leader election startup (unit: second) - startupGracePeriod: 15s - # Interval gossip membership samples to check its stability (unit: second) - membershipSampleInterval: 1s - # Time passes since last declaration message before peer decides to perform leader election (unit: second) - leaderAliveThreshold: 10s - # Time between peer sends propose message and declares itself as a leader (sends declaration message) (unit: second) - leaderElectionDuration: 5s - - pvtData: - # pullRetryThreshold determines the maximum duration of time private data corresponding for a given block - # would be attempted to be pulled from peers until the block would be committed without the private data - pullRetryThreshold: 60s - # As private data enters the transient store, it is associated with the peer's ledger's height at that time. - # transientstoreMaxBlockRetention defines the maximum difference between the current ledger's height upon commit, - # and the private data residing inside the transient store that is guaranteed not to be purged. - # Private data is purged from the transient store when blocks with sequences that are multiples - # of transientstoreMaxBlockRetention are committed. - transientstoreMaxBlockRetention: 1000 - # pushAckTimeout is the maximum time to wait for an acknowledgement from each peer - # at private data push at endorsement time. - pushAckTimeout: 3s - # Block to live pulling margin, used as a buffer - # to prevent peer from trying to pull private data - # from peers that is soon to be purged in next N blocks. - # This helps a newly joined peer catch up to current - # blockchain height quicker. - btlPullMargin: 10 - # the process of reconciliation is done in an endless loop, while in each iteration reconciler tries to - # pull from the other peers the most recent missing blocks with a maximum batch size limitation. - # reconcileBatchSize determines the maximum batch size of missing private data that will be reconciled in a - # single iteration. - reconcileBatchSize: 10 - # reconcileSleepInterval determines the time reconciler sleeps from end of an iteration until the beginning - # of the next reconciliation iteration. - reconcileSleepInterval: 1m - # reconciliationEnabled is a flag that indicates whether private data reconciliation is enable or not. - reconciliationEnabled: true - # skipPullingInvalidTransactionsDuringCommit is a flag that indicates whether pulling of invalid - # transaction's private data from other peers need to be skipped during the commit time and pulled - # only through reconciler. - skipPullingInvalidTransactionsDuringCommit: false - # implicitCollectionDisseminationPolicy specifies the dissemination policy for the peer's own implicit collection. - # When a peer endorses a proposal that writes to its own implicit collection, below values override the default values - # for disseminating private data. - # Note that it is applicable to all channels the peer has joined. The implication is that requiredPeerCount has to - # be smaller than the number of peers in a channel that has the lowest numbers of peers from the organization. - implicitCollectionDisseminationPolicy: - # requiredPeerCount defines the minimum number of eligible peers to which the peer must successfully - # disseminate private data for its own implicit collection during endorsement. Default value is 0. - requiredPeerCount: 0 - # maxPeerCount defines the maximum number of eligible peers to which the peer will attempt to - # disseminate private data for its own implicit collection during endorsement. Default value is 1. - maxPeerCount: 1 - - # Gossip state transfer related configuration - state: - # indicates whenever state transfer is enabled or not - # default value is true, i.e. state transfer is active - # and takes care to sync up missing blocks allowing - # lagging peer to catch up to speed with rest network. - # Keep in mind that when peer.gossip.useLeaderElection is true - # and there are several peers in the organization, - # or peer.gossip.useLeaderElection is false alongside with - # peer.gossip.orgleader being false, the peer's ledger may lag behind - # the rest of the peers and will never catch up due to state transfer - # being disabled. - enabled: false - # checkInterval interval to check whether peer is lagging behind enough to - # request blocks via state transfer from another peer. - checkInterval: 10s - # responseTimeout amount of time to wait for state transfer response from - # other peers - responseTimeout: 3s - # batchSize the number of blocks to request via state transfer from another peer - batchSize: 10 - # blockBufferSize reflects the size of the re-ordering buffer - # which captures blocks and takes care to deliver them in order - # down to the ledger layer. The actual buffer size is bounded between - # 0 and 2*blockBufferSize, each channel maintains its own buffer - blockBufferSize: 20 - # maxRetries maximum number of re-tries to ask - # for single state transfer request - maxRetries: 3 - - # TLS Settings - tls: - # Require server-side TLS - enabled: false - # Require client certificates / mutual TLS for inbound connections. - # Note that clients that are not configured to use a certificate will - # fail to connect to the peer. - clientAuthRequired: false - # X.509 certificate used for TLS server - cert: - file: tls/server.crt - # Private key used for TLS server - key: - file: tls/server.key - # rootcert.file represents the trusted root certificate chain used for verifying certificates - # of other nodes during outbound connections. - # It is not required to be set, but can be used to augment the set of TLS CA certificates - # available from the MSPs of each channel’s configuration. - rootcert: - file: tls/ca.crt - # If mutual TLS is enabled, clientRootCAs.files contains a list of additional root certificates - # used for verifying certificates of client connections. - # It augments the set of TLS CA certificates available from the MSPs of each channel’s configuration. - # Minimally, set your organization's TLS CA root certificate so that the peer can receive join channel requests. - clientRootCAs: - files: - - tls/ca.crt - # Private key used for TLS when making client connections. - # If not set, peer.tls.key.file will be used instead - clientKey: - file: - # X.509 certificate used for TLS when making client connections. - # If not set, peer.tls.cert.file will be used instead - clientCert: - file: - - # Authentication contains configuration parameters related to authenticating - # client messages - authentication: - # the acceptable difference between the current server time and the - # client's time as specified in a client request message - timewindow: 15m - - # Path on the file system where peer will store data (eg ledger). This - # location must be access control protected to prevent unintended - # modification that might corrupt the peer operations. - fileSystemPath: /var/hyperledger/production - - # BCCSP (Blockchain crypto provider): Select which crypto implementation or - # library to use - BCCSP: - Default: SW - # Settings for the SW crypto provider (i.e. when DEFAULT: SW) - SW: - # TODO: The default Hash and Security level needs refactoring to be - # fully configurable. Changing these defaults requires coordination - # SHA2 is hardcoded in several places, not only BCCSP - Hash: SHA2 - Security: 256 - # Location of Key Store - FileKeyStore: - # If "", defaults to 'mspConfigPath'/keystore - KeyStore: - # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) - PKCS11: - # Location of the PKCS11 module library - Library: - # Token Label - Label: - # User PIN - Pin: - Hash: - Security: - - # Path on the file system where peer will find MSP local configurations - mspConfigPath: msp - - # Identifier of the local MSP - # ----!!!!IMPORTANT!!!-!!!IMPORTANT!!!-!!!IMPORTANT!!!!---- - # Deployers need to change the value of the localMspId string. - # In particular, the name of the local MSP ID of a peer needs - # to match the name of one of the MSPs in each of the channel - # that this peer is a member of. Otherwise this peer's messages - # will not be identified as valid by other nodes. - localMspId: SampleOrg - - # CLI common client config options - client: - # connection timeout - connTimeout: 3s - - # Delivery service related config - deliveryclient: - # It sets the total time the delivery service may spend in reconnection - # attempts until its retry logic gives up and returns an error - reconnectTotalTimeThreshold: 3600s - - # It sets the delivery service <-> ordering service node connection timeout - connTimeout: 3s - - # It sets the delivery service maximal delay between consecutive retries - reConnectBackoffThreshold: 3600s - - # A list of orderer endpoint addresses which should be overridden - # when found in channel configurations. - addressOverrides: - # - from: - # to: - # caCertsFile: - # - from: - # to: - # caCertsFile: - - # Type for the local MSP - by default it's of type bccsp - localMspType: bccsp - - # Used with Go profiling tools only in none production environment. In - # production, it should be disabled (eg enabled: false) - profile: - enabled: false - listenAddress: 0.0.0.0:6060 - - # Handlers defines custom handlers that can filter and mutate - # objects passing within the peer, such as: - # Auth filter - reject or forward proposals from clients - # Decorators - append or mutate the chaincode input passed to the chaincode - # Endorsers - Custom signing over proposal response payload and its mutation - # Valid handler definition contains: - # - A name which is a factory method name defined in - # core/handlers/library/library.go for statically compiled handlers - # - library path to shared object binary for pluggable filters - # Auth filters and decorators are chained and executed in the order that - # they are defined. For example: - # authFilters: - # - - # name: FilterOne - # library: /opt/lib/filter.so - # - - # name: FilterTwo - # decorators: - # - - # name: DecoratorOne - # - - # name: DecoratorTwo - # library: /opt/lib/decorator.so - # Endorsers are configured as a map that its keys are the endorsement system chaincodes that are being overridden. - # Below is an example that overrides the default ESCC and uses an endorsement plugin that has the same functionality - # as the default ESCC. - # If the 'library' property is missing, the name is used as the constructor method in the builtin library similar - # to auth filters and decorators. - # endorsers: - # escc: - # name: DefaultESCC - # library: /etc/hyperledger/fabric/plugin/escc.so - handlers: - authFilters: - - - name: DefaultAuth - - - name: ExpirationCheck # This filter checks identity x509 certificate expiration - decorators: - - - name: DefaultDecorator - endorsers: - escc: - name: DefaultEndorsement - library: - validators: - vscc: - name: DefaultValidation - library: - - # library: /etc/hyperledger/fabric/plugin/escc.so - # Number of goroutines that will execute transaction validation in parallel. - # By default, the peer chooses the number of CPUs on the machine. Set this - # variable to override that choice. - # NOTE: overriding this value might negatively influence the performance of - # the peer so please change this value only if you know what you're doing - validatorPoolSize: - - # The discovery service is used by clients to query information about peers, - # such as - which peers have joined a certain channel, what is the latest - # channel config, and most importantly - given a chaincode and a channel, - # what possible sets of peers satisfy the endorsement policy. - discovery: - enabled: true - # Whether the authentication cache is enabled or not. - authCacheEnabled: true - # The maximum size of the cache, after which a purge takes place - authCacheMaxSize: 1000 - # The proportion (0 to 1) of entries that remain in the cache after the cache is purged due to overpopulation - authCachePurgeRetentionRatio: 0.75 - # Whether to allow non-admins to perform non channel scoped queries. - # When this is false, it means that only peer admins can perform non channel scoped queries. - orgMembersAllowedAccess: false - - # Limits is used to configure some internal resource limits. - limits: - # Concurrency limits the number of concurrently running requests to a service on each peer. - # Currently this option is only applied to endorser service and deliver service. - # When the property is missing or the value is 0, the concurrency limit is disabled for the service. - concurrency: - # endorserService limits concurrent requests to endorser service that handles chaincode deployment, query and invocation, - # including both user chaincodes and system chaincodes. - endorserService: 2500 - # deliverService limits concurrent event listeners registered to deliver service for blocks and transaction events. - deliverService: 2500 - -############################################################################### -# -# VM section -# -############################################################################### -vm: - - # Endpoint of the vm management system. For docker can be one of the following in general - # unix:///var/run/docker.sock - # http://localhost:2375 - # https://localhost:2376 - endpoint: unix:///var/run/docker.sock - - # settings for docker vms - docker: - tls: - enabled: false - ca: - file: docker/ca.crt - cert: - file: docker/tls.crt - key: - file: docker/tls.key - - # Enables/disables the standard out/err from chaincode containers for - # debugging purposes - attachStdout: false - - # Parameters on creating docker container. - # Container may be efficiently created using ipam & dns-server for cluster - # NetworkMode - sets the networking mode for the container. Supported - # standard values are: `host`(default),`bridge`,`ipvlan`,`none`. - # Dns - a list of DNS servers for the container to use. - # Note: `Privileged` `Binds` `Links` and `PortBindings` properties of - # Docker Host Config are not supported and will not be used if set. - # LogConfig - sets the logging driver (Type) and related options - # (Config) for Docker. For more info, - # https://docs.docker.com/engine/admin/logging/overview/ - # Note: Set LogConfig using Environment Variables is not supported. - hostConfig: - NetworkMode: host - Dns: - # - 192.168.0.1 - LogConfig: - Type: json-file - Config: - max-size: "50m" - max-file: "5" - Memory: 2147483648 - -############################################################################### -# -# Chaincode section -# -############################################################################### -chaincode: - - # The id is used by the Chaincode stub to register the executing Chaincode - # ID with the Peer and is generally supplied through ENV variables - # the `path` form of ID is provided when installing the chaincode. - # The `name` is used for all other requests and can be any string. - id: - path: - name: - - # Generic builder environment, suitable for most chaincode types - builder: $(DOCKER_NS)/fabric-ccenv:$(TWO_DIGIT_VERSION) - - # Enables/disables force pulling of the base docker images (listed below) - # during user chaincode instantiation. - # Useful when using moving image tags (such as :latest) - pull: false - - golang: - # golang will never need more than baseos - runtime: $(DOCKER_NS)/fabric-baseos:$(TWO_DIGIT_VERSION) - - # whether or not golang chaincode should be linked dynamically - dynamicLink: false - - java: - # This is an image based on java:openjdk-8 with addition compiler - # tools added for java shim layer packaging. - # This image is packed with shim layer libraries that are necessary - # for Java chaincode runtime. - runtime: $(DOCKER_NS)/fabric-javaenv:$(TWO_DIGIT_VERSION) - - node: - # This is an image based on node:$(NODE_VER)-alpine - runtime: $(DOCKER_NS)/fabric-nodeenv:$(TWO_DIGIT_VERSION) - - # 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: - - path: /var/hyperledger/fabric/chaincode/ccs-builder - name: ccs-builder - propagateEnvironment: - - HOME - - CORE_PEER_ID - - CORE_PEER_LOCALMSPID - - # The maximum duration to wait for the chaincode build and install process - # to complete. - installTimeout: 300s - - # Timeout duration for starting up a container and waiting for Register - # to come through. - startuptimeout: 300s - - # Timeout duration for Invoke and Init calls to prevent runaway. - # This timeout is used by all chaincodes in all the channels, including - # system chaincodes. - # Note that during Invoke, if the image is not available (e.g. being - # cleaned up when in development environment), the peer will automatically - # build the image, which might take more time. In production environment, - # the chaincode image is unlikely to be deleted, so the timeout could be - # reduced accordingly. - executetimeout: 30s - - # There are 2 modes: "dev" and "net". - # In dev mode, user runs the chaincode after starting peer from - # command line on local machine. - # In net mode, peer will run chaincode in a docker container. - mode: net - - # keepalive in seconds. In situations where the communication goes through a - # proxy that does not support keep-alive, this parameter will maintain connection - # between peer and chaincode. - # A value <= 0 turns keepalive off - keepalive: 0 - - # enabled system chaincodes - system: - _lifecycle: enable - cscc: enable - lscc: enable - qscc: enable - - # Logging section for the chaincode container - logging: - # Default level for all loggers within the chaincode container - level: info - # Override default level for the 'shim' logger - shim: warning - # Format for the chaincode container logs - format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}' - -############################################################################### -# -# Ledger section - ledger configuration encompasses both the blockchain -# and the state -# -############################################################################### -ledger: - - blockchain: - - state: - # stateDatabase - options are "goleveldb", "CouchDB" - # goleveldb - default state database stored in goleveldb. - # CouchDB - store state database in CouchDB - stateDatabase: goleveldb - # Limit on the number of records to return per query - totalQueryLimit: 100000 - couchDBConfig: - # It is recommended to run CouchDB on the same server as the peer, and - # not map the CouchDB container port to a server port in docker-compose. - # Otherwise proper security must be provided on the connection between - # CouchDB client (on the peer) and server. - couchDBAddress: 127.0.0.1:5984 - # This username must have read and write authority on CouchDB - username: - # The password is recommended to pass as an environment variable - # during start up (eg CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD). - # If it is stored here, the file must be access control protected - # to prevent unintended users from discovering the password. - password: - # Number of retries for CouchDB errors - maxRetries: 3 - # Number of retries for CouchDB errors during peer startup. - # The delay between retries doubles for each attempt. - # Default of 10 retries results in 11 attempts over 2 minutes. - maxRetriesOnStartup: 10 - # CouchDB request timeout (unit: duration, e.g. 20s) - requestTimeout: 35s - # Limit on the number of records per each CouchDB query - # Note that chaincode queries are only bound by totalQueryLimit. - # Internally the chaincode may execute multiple CouchDB queries, - # each of size internalQueryLimit. - internalQueryLimit: 1000 - # Limit on the number of records per CouchDB bulk update batch - maxBatchUpdateSize: 1000 - # Warm indexes after every N blocks. - # This option warms any indexes that have been - # deployed to CouchDB after every N blocks. - # A value of 1 will warm indexes after every block commit, - # to ensure fast selector queries. - # Increasing the value may improve write efficiency of peer and CouchDB, - # but may degrade query response time. - warmIndexesAfterNBlocks: 1 - # Create the _global_changes system database - # This is optional. Creating the global changes database will require - # additional system resources to track changes and maintain the database - createGlobalChangesDB: false - # CacheSize denotes the maximum mega bytes (MB) to be allocated for the in-memory state - # cache. Note that CacheSize needs to be a multiple of 32 MB. If it is not a multiple - # of 32 MB, the peer would round the size to the next multiple of 32 MB. - # To disable the cache, 0 MB needs to be assigned to the cacheSize. - cacheSize: 64 - - history: - # enableHistoryDatabase - options are true or false - # Indicates if the history of key updates should be stored. - # All history 'index' will be stored in goleveldb, regardless if using - # CouchDB or alternate database for the state. - enableHistoryDatabase: true - - pvtdataStore: - # the maximum db batch size for converting - # the ineligible missing data entries to eligible missing data entries - collElgProcMaxDbBatchSize: 5000 - # the minimum duration (in milliseconds) between writing - # two consecutive db batches for converting the ineligible missing data entries to eligible missing data entries - collElgProcDbBatchesInterval: 1000 - # The missing data entries are classified into two categories: - # (1) prioritized - # (2) deprioritized - # Initially, all missing data are in the prioritized list. When the - # reconciler is unable to fetch the missing data from other peers, - # the unreconciled missing data would be moved to the deprioritized list. - # The reconciler would retry deprioritized missing data after every - # deprioritizedDataReconcilerInterval (unit: minutes). Note that the - # interval needs to be greater than the reconcileSleepInterval - deprioritizedDataReconcilerInterval: 60m - - snapshots: - # Path on the file system where peer will store ledger snapshots - rootDir: /var/hyperledger/production/snapshots - -############################################################################### -# -# Operations section -# -############################################################################### -operations: - # host and port for the operations server - listenAddress: 127.0.0.1:9443 - - # TLS configuration for the operations endpoint - tls: - # TLS enabled - enabled: false - - # path to PEM encoded server certificate for the operations server - cert: - file: - - # path to PEM encoded server key for the operations server - key: - file: - - # most operations service endpoints require client authentication when TLS - # is enabled. clientAuthRequired requires client certificate authentication - # at the TLS layer to access all resources. - clientAuthRequired: false - - # paths to PEM encoded ca certificates to trust for client authentication - clientRootCAs: - files: [] - -############################################################################### -# -# Metrics section -# -############################################################################### -metrics: - # metrics provider is one of statsd, prometheus, or disabled - provider: disabled - - # statsd configuration - statsd: - # network type: tcp or udp - network: udp - - # statsd server address - address: 127.0.0.1:8125 - - # the interval at which locally cached counters and gauges are pushed - # to statsd; timings are pushed immediately - writeInterval: 10s - - # prefix is prepended to all emitted statsd metrics - prefix: diff --git a/test-network-kind/config/crypto-config.yaml b/test-network-kind/config/crypto-config.yaml deleted file mode 100644 index c7f5178e..00000000 --- a/test-network-kind/config/crypto-config.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# - -# --------------------------------------------------------------------------- -# "OrdererOrgs" - Definition of organizations managing orderer nodes -# --------------------------------------------------------------------------- -OrdererOrgs: - - Name: Orderer - Domain: example.com - EnableNodeOUs: true - - Specs: - - Hostname: orderer1 - SANS: - - 0.0.0.0 - - Hostname: orderer2 - SANS: - - 0.0.0.0 - - Hostname: orderer3 - SANS: - - 0.0.0.0 - - Hostname: orderer4 - SANS: - - 0.0.0.0 - - Hostname: orderer5 - SANS: - - 0.0.0.0 - -# --------------------------------------------------------------------------- -# "PeerOrgs" - Definition of organizations managing peer nodes -# --------------------------------------------------------------------------- -PeerOrgs: - - Name: Org1 - Domain: org1.example.com - EnableNodeOUs: true - Specs: - - Hostname: org1-peer1 - SANS: - - 0.0.0.0 - - Hostname: org1-peer2 - SANS: - - 0.0.0.0 - Users: - Count: 1 - - - Name: Org2 - Domain: org2.example.com - EnableNodeOUs: true - Specs: - - Hostname: org2-peer1 - SANS: - - 0.0.0.0 - - Hostname: org2-peer2 - SANS: - - 0.0.0.0 - Users: - Count: 1 diff --git a/test-network-kind/config/orderer.yaml b/test-network-kind/config/orderer.yaml deleted file mode 100644 index fc545546..00000000 --- a/test-network-kind/config/orderer.yaml +++ /dev/null @@ -1,420 +0,0 @@ -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# - - ---- -################################################################################ -# -# Orderer Configuration -# -# - This controls the type and configuration of the orderer. -# -################################################################################ -General: - # Listen address: The IP on which to bind to listen. - ListenAddress: 127.0.0.1 - - # Listen port: The port on which to bind to listen. - ListenPort: 7050 - - # TLS: TLS settings for the GRPC server. - TLS: - # Require server-side TLS - Enabled: false - # PrivateKey governs the file location of the private key of the TLS certificate. - PrivateKey: tls/server.key - # Certificate governs the file location of the server TLS certificate. - Certificate: tls/server.crt - # RootCAs contains a list of additional root certificates used for verifying certificates - # of other orderer nodes during outbound connections. - # It is not required to be set, but can be used to augment the set of TLS CA certificates - # available from the MSPs of each channel’s configuration. - RootCAs: - - tls/ca.crt - # Require client certificates / mutual TLS for inbound connections. - ClientAuthRequired: false - # If mutual TLS is enabled, ClientRootCAs contains a list of additional root certificates - # used for verifying certificates of client connections. - # It is not required to be set, but can be used to augment the set of TLS CA certificates - # available from the MSPs of each channel’s configuration. - ClientRootCAs: - # Keepalive settings for the GRPC server. - Keepalive: - # ServerMinInterval is the minimum permitted time between client pings. - # If clients send pings more frequently, the server will - # disconnect them. - ServerMinInterval: 60s - # ServerInterval is the time between pings to clients. - ServerInterval: 7200s - # ServerTimeout is the duration the server waits for a response from - # a client before closing the connection. - ServerTimeout: 20s - # Cluster settings for ordering service nodes that communicate with other ordering service nodes - # such as Raft based ordering service. - Cluster: - # SendBufferSize is the maximum number of messages in the egress buffer. - # Consensus messages are dropped if the buffer is full, and transaction - # messages are waiting for space to be freed. - SendBufferSize: 10 - - # ClientCertificate governs the file location of the client TLS certificate - # used to establish mutual TLS connections with other ordering service nodes. - # If not set, the server General.TLS.Certificate is re-used. - ClientCertificate: - # ClientPrivateKey governs the file location of the private key of the client TLS certificate. - # If not set, the server General.TLS.PrivateKey is re-used. - ClientPrivateKey: - - # The below 4 properties should be either set together, or be unset together. - # If they are set, then the orderer node uses a separate listener for intra-cluster - # communication. If they are unset, then the general orderer listener is used. - # This is useful if you want to use a different TLS server certificates on the - # client-facing and the intra-cluster listeners. - - # ListenPort defines the port on which the cluster listens to connections. - ListenPort: - # ListenAddress defines the IP on which to listen to intra-cluster communication. - ListenAddress: - # ServerCertificate defines the file location of the server TLS certificate used for intra-cluster - # communication. - ServerCertificate: - # ServerPrivateKey defines the file location of the private key of the TLS certificate. - ServerPrivateKey: - - # Bootstrap method: The method by which to obtain the bootstrap block - # system channel is specified. The option can be one of: - # "file" - path to a file containing the genesis block or config block of system channel - # "none" - allows an orderer to start without a system channel configuration - BootstrapMethod: file - - # Bootstrap file: The file containing the bootstrap block to use when - # initializing the orderer system channel and BootstrapMethod is set to - # "file". The bootstrap file can be the genesis block, and it can also be - # a config block for late bootstrap of some consensus methods like Raft. - # Generate a genesis block by updating $FABRIC_CFG_PATH/configtx.yaml and - # using configtxgen command with "-outputBlock" option. - # Defaults to file "genesisblock" (in $FABRIC_CFG_PATH directory) if not specified. - BootstrapFile: - - # LocalMSPDir is where to find the private crypto material needed by the - # orderer. It is set relative here as a default for dev environments but - # should be changed to the real location in production. - LocalMSPDir: msp - - # LocalMSPID is the identity to register the local MSP material with the MSP - # manager. IMPORTANT: The local MSP ID of an orderer needs to match the MSP - # ID of one of the organizations defined in the orderer system channel's - # /Channel/Orderer configuration. The sample organization defined in the - # sample configuration provided has an MSP ID of "SampleOrg". - LocalMSPID: SampleOrg - - # Enable an HTTP service for Go "pprof" profiling as documented at: - # https://golang.org/pkg/net/http/pprof - Profile: - Enabled: false - Address: 0.0.0.0:6060 - - # BCCSP configures the blockchain crypto service providers. - BCCSP: - # Default specifies the preferred blockchain crypto service provider - # to use. If the preferred provider is not available, the software - # based provider ("SW") will be used. - # Valid providers are: - # - SW: a software based crypto provider - # - PKCS11: a CA hardware security module crypto provider. - Default: SW - - # SW configures the software based blockchain crypto provider. - SW: - # TODO: The default Hash and Security level needs refactoring to be - # fully configurable. Changing these defaults requires coordination - # SHA2 is hardcoded in several places, not only BCCSP - Hash: SHA2 - Security: 256 - # Location of key store. If this is unset, a location will be - # chosen using: 'LocalMSPDir'/keystore - FileKeyStore: - KeyStore: - - # Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11) - PKCS11: - # Location of the PKCS11 module library - Library: - # Token Label - Label: - # User PIN - Pin: - Hash: - Security: - FileKeyStore: - KeyStore: - - # Authentication contains configuration parameters related to authenticating - # client messages - Authentication: - # the acceptable difference between the current server time and the - # client's time as specified in a client request message - TimeWindow: 15m - - -################################################################################ -# -# SECTION: File Ledger -# -# - This section applies to the configuration of the file ledger. -# -################################################################################ -FileLedger: - - # Location: The directory to store the blocks in. - Location: /var/hyperledger/production/orderer - -################################################################################ -# -# SECTION: Kafka -# -# - This section applies to the configuration of the Kafka-based orderer, and -# its interaction with the Kafka cluster. -# -################################################################################ -Kafka: - - # Retry: What do if a connection to the Kafka cluster cannot be established, - # or if a metadata request to the Kafka cluster needs to be repeated. - Retry: - # When a new channel is created, or when an existing channel is reloaded - # (in case of a just-restarted orderer), the orderer interacts with the - # Kafka cluster in the following ways: - # 1. It creates a Kafka producer (writer) for the Kafka partition that - # corresponds to the channel. - # 2. It uses that producer to post a no-op CONNECT message to that - # partition - # 3. It creates a Kafka consumer (reader) for that partition. - # If any of these steps fail, they will be re-attempted every - # for a total of , and then every - # for a total of until they succeed. - # Note that the orderer will be unable to write to or read from a - # channel until all of the steps above have been completed successfully. - ShortInterval: 5s - ShortTotal: 10m - LongInterval: 5m - LongTotal: 12h - # Affects the socket timeouts when waiting for an initial connection, a - # response, or a transmission. See Config.Net for more info: - # https://godoc.org/github.com/Shopify/sarama#Config - NetworkTimeouts: - DialTimeout: 10s - ReadTimeout: 10s - WriteTimeout: 10s - # Affects the metadata requests when the Kafka cluster is in the middle - # of a leader election.See Config.Metadata for more info: - # https://godoc.org/github.com/Shopify/sarama#Config - Metadata: - RetryBackoff: 250ms - RetryMax: 3 - # What to do if posting a message to the Kafka cluster fails. See - # Config.Producer for more info: - # https://godoc.org/github.com/Shopify/sarama#Config - Producer: - RetryBackoff: 100ms - RetryMax: 3 - # What to do if reading from the Kafka cluster fails. See - # Config.Consumer for more info: - # https://godoc.org/github.com/Shopify/sarama#Config - Consumer: - RetryBackoff: 2s - # Settings to use when creating Kafka topics. Only applies when - # Kafka.Version is v0.10.1.0 or higher - Topic: - # The number of Kafka brokers across which to replicate the topic - ReplicationFactor: 3 - # Verbose: Enable logging for interactions with the Kafka cluster. - Verbose: false - - # TLS: TLS settings for the orderer's connection to the Kafka cluster. - TLS: - - # Enabled: Use TLS when connecting to the Kafka cluster. - Enabled: false - - # PrivateKey: PEM-encoded private key the orderer will use for - # authentication. - PrivateKey: - # As an alternative to specifying the PrivateKey here, uncomment the - # following "File" key and specify the file name from which to load the - # value of PrivateKey. - #File: path/to/PrivateKey - - # Certificate: PEM-encoded signed public key certificate the orderer will - # use for authentication. - Certificate: - # As an alternative to specifying the Certificate here, uncomment the - # following "File" key and specify the file name from which to load the - # value of Certificate. - #File: path/to/Certificate - - # RootCAs: PEM-encoded trusted root certificates used to validate - # certificates from the Kafka cluster. - RootCAs: - # As an alternative to specifying the RootCAs here, uncomment the - # following "File" key and specify the file name from which to load the - # value of RootCAs. - #File: path/to/RootCAs - - # SASLPlain: Settings for using SASL/PLAIN authentication with Kafka brokers - SASLPlain: - # Enabled: Use SASL/PLAIN to authenticate with Kafka brokers - Enabled: false - # User: Required when Enabled is set to true - User: - # Password: Required when Enabled is set to true - Password: - - # Kafka protocol version used to communicate with the Kafka cluster brokers - # (defaults to 0.10.2.0 if not specified) - Version: - -################################################################################ -# -# Debug Configuration -# -# - This controls the debugging options for the orderer -# -################################################################################ -Debug: - - # BroadcastTraceDir when set will cause each request to the Broadcast service - # for this orderer to be written to a file in this directory - BroadcastTraceDir: - - # DeliverTraceDir when set will cause each request to the Deliver service - # for this orderer to be written to a file in this directory - DeliverTraceDir: - -################################################################################ -# -# Operations Configuration -# -# - This configures the operations server endpoint for the orderer -# -################################################################################ -Operations: - # host and port for the operations server - ListenAddress: 127.0.0.1:8443 - - # TLS configuration for the operations endpoint - TLS: - # TLS enabled - Enabled: false - - # Certificate is the location of the PEM encoded TLS certificate - Certificate: - - # PrivateKey points to the location of the PEM-encoded key - PrivateKey: - - # Most operations service endpoints require client authentication when TLS - # is enabled. ClientAuthRequired requires client certificate authentication - # at the TLS layer to access all resources. - ClientAuthRequired: false - - # Paths to PEM encoded ca certificates to trust for client authentication - ClientRootCAs: [] - -################################################################################ -# -# Metrics Configuration -# -# - This configures metrics collection for the orderer -# -################################################################################ -Metrics: - # The metrics provider is one of statsd, prometheus, or disabled - Provider: disabled - - # The statsd configuration - Statsd: - # network type: tcp or udp - Network: udp - - # the statsd server address - Address: 127.0.0.1:8125 - - # The interval at which locally cached counters and gauges are pushed - # to statsd; timings are pushed immediately - WriteInterval: 30s - - # The prefix is prepended to all emitted statsd metrics - Prefix: - -################################################################################ -# -# Admin Configuration -# -# - This configures the admin server endpoint for the orderer -# -################################################################################ -Admin: - # host and port for the admin server - ListenAddress: 127.0.0.1:9443 - - # TLS configuration for the admin endpoint - TLS: - # TLS enabled - Enabled: false - - # Certificate is the location of the PEM encoded TLS certificate - Certificate: - - # PrivateKey points to the location of the PEM-encoded key - PrivateKey: - - # Most admin service endpoints require client authentication when TLS - # is enabled. ClientAuthRequired requires client certificate authentication - # at the TLS layer to access all resources. - # - # NOTE: When TLS is enabled, the admin endpoint requires mutual TLS. The - # orderer will panic on startup if this value is set to false. - ClientAuthRequired: true - - # Paths to PEM encoded ca certificates to trust for client authentication - ClientRootCAs: [] - -################################################################################ -# -# Channel participation API Configuration -# -# - This provides the channel participation API configuration for the orderer. -# - Channel participation uses the ListenAddress and TLS settings of the Admin -# service. -# -################################################################################ -ChannelParticipation: - # Channel participation API is enabled. - Enabled: false - - # The maximum size of the request body when joining a channel. - MaxRequestBodySize: 1 MB - - -################################################################################ -# -# Consensus Configuration -# -# - This section contains config options for a consensus plugin. It is opaque -# to orderer, and completely up to consensus implementation to make use of. -# -################################################################################ -Consensus: - # The allowed key-value pairs here depend on consensus plugin. For etcd/raft, - # we use following options: - - # WALDir specifies the location at which Write Ahead Logs for etcd/raft are - # stored. Each channel will have its own subdir named after channel ID. - WALDir: /var/hyperledger/production/orderer/etcdraft/wal - - # SnapDir specifies the location at which snapshots for etcd/raft are - # stored. Each channel will have its own subdir named after channel ID. - SnapDir: /var/hyperledger/production/orderer/etcdraft/snapshot diff --git a/test-network-kind/kube/cc-asset-transfer-basic.yaml b/test-network-kind/kube/cc-asset-transfer-basic.yaml deleted file mode 100644 index 8760949b..00000000 --- a/test-network-kind/kube/cc-asset-transfer-basic.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cc-asset-transfer-basic -spec: - replicas: 1 - selector: - matchLabels: - app: cc-asset-transfer-basic - template: - metadata: - labels: - app: cc-asset-transfer-basic - spec: - containers: - - name: main - image: hyperledger/asset-transfer-basic - imagePullPolicy: IfNotPresent - env: - - name: CHAINCODE_SERVER_ADDRESS - value: 0.0.0.0:9999 - - # todo: load with an envFrom and a dynamic config map with the ID. - - name: CHAINCODE_ID - value: basic_1.0:d730a5ce916e120f2a2509ee33527a0df68cadac678f5eb196737ad10ba42da9 - ports: - - containerPort: 9999 - ---- -apiVersion: v1 -kind: Service -metadata: - name: cc-asset-transfer-basic -spec: - ports: - - name: chaincode - port: 9999 - protocol: TCP - selector: - app: cc-asset-transfer-basic \ No newline at end of file diff --git a/test-network-kind/kube/debug.yaml b/test-network-kind/kube/debug.yaml deleted file mode 100644 index 2adbae51..00000000 --- a/test-network-kind/kube/debug.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: debug - name: debug - namespace: test-network -spec: - progressDeadlineSeconds: 600 - replicas: 1 - selector: - matchLabels: - run: debug - strategy: - rollingUpdate: - maxSurge: 25% - maxUnavailable: 25% - type: RollingUpdate - template: - metadata: - labels: - run: debug - spec: - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 - containers: - - image: radial/busyboxplus:curl - imagePullPolicy: Always - name: main - resources: {} - stdin: true - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - tty: true - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: fabric-config - mountPath: /var/hyperledger/fabric/config - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: fabric-config - configMap: - name: fabric-config diff --git a/test-network-kind/kube/job-create-channel-config.yaml b/test-network-kind/kube/job-create-channel-config.yaml deleted file mode 100644 index bd445527..00000000 --- a/test-network-kind/kube/job-create-channel-config.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: batch/v1 -kind: Job -metadata: - generateName: create-channel-config- -spec: - backoffLimit: 1 - template: - metadata: - name: create-channel-config - spec: - restartPolicy: "Never" - containers: - - name: main - image: hyperledger/fabric-tools:2.3.2 - # todo: latest tag is not at docker hub - imagePullPolicy: Always - env: - - name: FABRIC_CFG_PATH - value: /var/hyperledger/fabric - command: [ - "configtxgen", - "-channelID", "mychannel", - "-profile", "TwoOrgsChannel", - "-outputCreateChannelTx", "/var/hyperledger/fabric/channel-artifacts/mychannel.tx", - ] - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: config-volume - mountPath: /var/hyperledger/fabric/configtx.yaml - subPath: configtx.yaml - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: config-volume - configMap: - name: fabric-config - diff --git a/test-network-kind/kube/job-crypto-config.yaml b/test-network-kind/kube/job-crypto-config.yaml deleted file mode 100644 index 7a9d6278..00000000 --- a/test-network-kind/kube/job-crypto-config.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: batch/v1 -kind: Job -metadata: - generateName: crypto-config- -spec: - backoffLimit: 1 - template: - metadata: - name: crypto-config - spec: - restartPolicy: "Never" - containers: - - name: main - image: hyperledger/fabric-tools:2.3.2 - # todo: fixme for KIND clusters - imagePullPolicy: Always - command: - - cryptogen - - generate - - --config=/var/hyperledger/fabric/crypto-config.yaml - - --output=/var/hyperledger/fabric/crypto-config - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: config-volume - mountPath: /var/hyperledger/fabric/crypto-config.yaml - subPath: crypto-config.yaml - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: config-volume - configMap: - name: fabric-config - diff --git a/test-network-kind/kube/job-orderer-genesis.yaml b/test-network-kind/kube/job-orderer-genesis.yaml deleted file mode 100644 index 089f699e..00000000 --- a/test-network-kind/kube/job-orderer-genesis.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: batch/v1 -kind: Job -metadata: - generateName: orderer-genesis- -spec: - backoffLimit: 1 - template: - metadata: - name: orderer-genesis - spec: - restartPolicy: "Never" - containers: - - name: main - image: hyperledger/fabric-tools:2.3.2 - # todo: latest tag is not at docker hub - imagePullPolicy: Always - env: - - name: FABRIC_CFG_PATH - value: /var/hyperledger/fabric - command: [ - "configtxgen", - "-profile", "TwoOrgsOrdererGenesis", - "-channelID", "test-system-channel-name", - "-outputBlock", "/var/hyperledger/fabric/channel-artifacts/genesis.block" - ] - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: config-volume - mountPath: /var/hyperledger/fabric/configtx.yaml - subPath: configtx.yaml - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: config-volume - configMap: - name: fabric-config \ No newline at end of file diff --git a/test-network-kind/kube/job-scrub-fabric-volume.yaml b/test-network-kind/kube/job-scrub-fabric-volume.yaml deleted file mode 100644 index 1ad56bd0..00000000 --- a/test-network-kind/kube/job-scrub-fabric-volume.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: job-scrub-fabric-volume -spec: - backoffLimit: 0 - completions: 1 - template: - metadata: - name: scrub-fabric-volume - spec: - restartPolicy: "Never" - containers: - - name: main - image: alpine - command: - - sh - - -c - - "rm -rvf /var/hyperledger/fabric/*" - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric \ No newline at end of file diff --git a/test-network-kind/kube/job-update-org1-anchor-peers.yaml b/test-network-kind/kube/job-update-org1-anchor-peers.yaml deleted file mode 100644 index cc87a402..00000000 --- a/test-network-kind/kube/job-update-org1-anchor-peers.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: batch/v1 -kind: Job -metadata: - generateName: update-org1-anchor-peers- -spec: - backoffLimit: 1 - template: - metadata: - name: update-org1-anchor-peers - spec: - restartPolicy: "Never" - containers: - - name: main - image: hyperledger/fabric-tools:2.3.2 - # todo: latest tag is not at docker hub - imagePullPolicy: Always - env: - - name: FABRIC_CFG_PATH - value: /var/hyperledger/fabric - command: [ - "configtxgen", - "-profile", "TwoOrgsChannel", - "-outputAnchorPeersUpdate", "/var/hyperledger/fabric/channel-artifacts/Org1MSPanchors.tx", - "-channelID", "mychannel", - "-asOrg", "Org1MSP", - ] - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: config-volume - mountPath: /var/hyperledger/fabric/configtx.yaml - subPath: configtx.yaml - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: config-volume - configMap: - name: fabric-config \ No newline at end of file diff --git a/test-network-kind/kube/job-update-org2-anchor-peers.yaml b/test-network-kind/kube/job-update-org2-anchor-peers.yaml deleted file mode 100644 index af32bc28..00000000 --- a/test-network-kind/kube/job-update-org2-anchor-peers.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: batch/v1 -kind: Job -metadata: - generateName: update-org2-anchor-peers- -spec: - backoffLimit: 1 - template: - metadata: - name: update-org2-anchor-peers - spec: - restartPolicy: "Never" - containers: - - name: main - image: hyperledger/fabric-tools:2.3.2 - # todo: latest tag is not at docker hub - imagePullPolicy: Always - env: - - name: FABRIC_CFG_PATH - value: /var/hyperledger/fabric - command: [ - "configtxgen", - "-profile", "TwoOrgsChannel", - "-outputAnchorPeersUpdate", "/var/hyperledger/fabric/channel-artifacts/Org2MSPanchors.tx", - "-channelID", "mychannel", - "-asOrg", "Org2MSP", - ] - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: config-volume - mountPath: /var/hyperledger/fabric/configtx.yaml - subPath: configtx.yaml - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: config-volume - configMap: - name: fabric-config diff --git a/test-network-kind/kube/ns-test-network.yaml b/test-network-kind/kube/ns-test-network.yaml deleted file mode 100644 index f9ef39e0..00000000 --- a/test-network-kind/kube/ns-test-network.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: Namespace -metadata: - name: test-network diff --git a/test-network-kind/kube/orderer1.yaml b/test-network-kind/kube/orderer1.yaml deleted file mode 100644 index 2b1503e1..00000000 --- a/test-network-kind/kube/orderer1.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: orderer1-config -data: - FABRIC_CFG_PATH: /var/hyperledger/fabric/config - FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info" - ORDERER_GENERAL_LISTENADDRESS: "0.0.0.0" - ORDERER_GENERAL_LISTENPORT: "6050" - ORDERER_GENERAL_LOCALMSPID: OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/msp - ORDERER_GENERAL_TLS_ENABLED: "true" - ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.key - ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt - # following setting is not really needed at runtime since channel config has ca root certs, but we need to override the default in orderer.yaml - ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/ca.crt - ORDERER_GENERAL_BOOTSTRAPMETHOD: file - ORDERER_GENERAL_BOOTSTRAPFILE: /var/hyperledger/fabric/channel-artifacts/genesis.block - ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer - ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer/etcdraft/wal - ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer/etcdraft/wal - ORDERER_OPERATIONS_LISTENADDRESS: "0.0.0.0:8443" - ORDERER_ADMIN_LISTENADDRESS: "0.0.0.0:9443" - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: orderer1 -spec: - replicas: 1 - selector: - matchLabels: - app: orderer1 - template: - metadata: - labels: - app: orderer1 - spec: - containers: - - name: main - image: hyperledger/fabric-orderer:2.3.2 - imagePullPolicy: Always - envFrom: - - configMapRef: - name: orderer1-config - ports: - - containerPort: 6050 - - containerPort: 8443 - - containerPort: 9443 - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: fabric-config - mountPath: /var/hyperledger/fabric/config - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: fabric-config - configMap: - name: fabric-config - ---- -apiVersion: v1 -kind: Service -metadata: - name: orderer1 -spec: - ports: - - name: general - port: 6050 - protocol: TCP - - name: operations - port: 8443 - protocol: TCP - - name: admin - port: 9443 - protocol: TCP - selector: - app: orderer1 \ No newline at end of file diff --git a/test-network-kind/kube/orderer2.yaml b/test-network-kind/kube/orderer2.yaml deleted file mode 100644 index cc2636b5..00000000 --- a/test-network-kind/kube/orderer2.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: orderer2-config -data: - FABRIC_CFG_PATH: /var/hyperledger/fabric/config - FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info" - ORDERER_GENERAL_LISTENADDRESS: "0.0.0.0" - ORDERER_GENERAL_LISTENPORT: "6050" - ORDERER_GENERAL_LOCALMSPID: OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/msp - ORDERER_GENERAL_TLS_ENABLED: "true" - ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.key - ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt - # following setting is not really needed at runtime since channel config has ca root certs, but we need to override the default in orderer.yaml - ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/ca.crt - ORDERER_GENERAL_BOOTSTRAPMETHOD: file - ORDERER_GENERAL_BOOTSTRAPFILE: /var/hyperledger/fabric/channel-artifacts/genesis.block - ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer2 - ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer2/etcdraft/wal - ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer2/etcdraft/wal - ORDERER_OPERATIONS_LISTENADDRESS: "0.0.0.0:8443" - ORDERER_ADMIN_LISTENADDRESS: "0.0.0.0:9443" - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: orderer2 -spec: - replicas: 1 - selector: - matchLabels: - app: orderer2 - template: - metadata: - labels: - app: orderer2 - spec: - containers: - - name: main - image: hyperledger/fabric-orderer:2.3.2 - imagePullPolicy: Always - envFrom: - - configMapRef: - name: orderer2-config - ports: - - containerPort: 6050 - - containerPort: 8443 - - containerPort: 9443 - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: fabric-config - mountPath: /var/hyperledger/fabric/config - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: fabric-config - configMap: - name: fabric-config - ---- -apiVersion: v1 -kind: Service -metadata: - name: orderer2 -spec: - ports: - - name: general - port: 6050 - protocol: TCP - - name: operations - port: 8443 - protocol: TCP - - name: admin - port: 9443 - protocol: TCP - selector: - app: orderer2 \ No newline at end of file diff --git a/test-network-kind/kube/orderer3.yaml b/test-network-kind/kube/orderer3.yaml deleted file mode 100644 index 0d53fc6d..00000000 --- a/test-network-kind/kube/orderer3.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: orderer3-config -data: - FABRIC_CFG_PATH: /var/hyperledger/fabric/config - FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,common.configtx,common.channelconfig=info" - ORDERER_GENERAL_LISTENADDRESS: "0.0.0.0" - ORDERER_GENERAL_LISTENPORT: "6050" - ORDERER_GENERAL_LOCALMSPID: OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/msp - ORDERER_GENERAL_TLS_ENABLED: "true" - ORDERER_GENERAL_TLS_PRIVATEKEY: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/server.key - ORDERER_GENERAL_TLS_CERTIFICATE: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/server.crt - # following setting is not really needed at runtime since channel config has ca root certs, but we need to override the default in orderer.yaml - ORDERER_GENERAL_TLS_ROOTCAS: /var/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/ca.crt - ORDERER_GENERAL_BOOTSTRAPMETHOD: file - ORDERER_GENERAL_BOOTSTRAPFILE: /var/hyperledger/fabric/channel-artifacts/genesis.block - ORDERER_FILELEDGER_LOCATION: /var/hyperledger/fabric/data/orderer3 - ORDERER_CONSENSUS_WALDIR: /var/hyperledger/fabric/data/orderer3/etcdraft/wal - ORDERER_CONSENSUS_SNAPDIR: /var/hyperledger/fabric/data/orderer3/etcdraft/wal - ORDERER_OPERATIONS_LISTENADDRESS: "0.0.0.0:8443" - ORDERER_ADMIN_LISTENADDRESS: "0.0.0.0:9443" - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: orderer3 -spec: - replicas: 1 - selector: - matchLabels: - app: orderer3 - template: - metadata: - labels: - app: orderer3 - spec: - containers: - - name: main - image: hyperledger/fabric-orderer:2.3.2 - imagePullPolicy: Always - envFrom: - - configMapRef: - name: orderer3-config - ports: - - containerPort: 6050 - - containerPort: 8443 - - containerPort: 9443 - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: fabric-config - mountPath: /var/hyperledger/fabric/config - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: fabric-config - configMap: - name: fabric-config - ---- -apiVersion: v1 -kind: Service -metadata: - name: orderer3 -spec: - ports: - - name: general - port: 6050 - protocol: TCP - - name: operations - port: 8443 - protocol: TCP - - name: admin - port: 9443 - protocol: TCP - selector: - app: orderer3 \ No newline at end of file diff --git a/test-network-kind/kube/org1-peer1.yaml b/test-network-kind/kube/org1-peer1.yaml deleted file mode 100644 index 78c09db5..00000000 --- a/test-network-kind/kube/org1-peer1.yaml +++ /dev/null @@ -1,110 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: org1-peer1-config -data: - FABRIC_CFG_PATH: /var/hyperledger/fabric/config - FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" - CORE_PEER_TLS_ENABLED: "true" - CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/server.crt - CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/tls/ca.crt - CORE_PEER_ID: org1-peer1.org1.example.com - CORE_PEER_ADDRESS: org1-peer1:7051 - CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS: org1-peer1:7052 - CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 - # bootstrap peer is the other peer in the same org - CORE_PEER_GOSSIP_BOOTSTRAP: org1-peer2:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT: org1-peer1:7051 - CORE_PEER_LOCALMSPID: Org1MSP - CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/msp - CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 - CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org1-peer1.org1.example.com - CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org1-peer1.org1.example.com/snapshots - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: org1-peer1 -spec: - replicas: 1 - selector: - matchLabels: - app: org1-peer1 - template: - metadata: - labels: - app: org1-peer1 - spec: - containers: - - name: main - image: hyperledger/fabric-peer:2.3.2 - imagePullPolicy: Always - envFrom: - - configMapRef: - name: org1-peer1-config - ports: - - containerPort: 7051 - - containerPort: 7052 - - containerPort: 9443 - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: fabric-config - mountPath: /var/hyperledger/fabric/config - - name: ccs-builder - mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin - - name: chaincode-config - mountPath: /var/hyperledger/fabric/chaincode/ - - # load the external chaincode builder into the peer image prior to peer launch. - initContainers: - - name: fabric-ccs-builder - # todo: publish this image to docker hub. It's currently read from the kind docker context. - image: hyperledgendary/fabric-ccs-builder - imagePullPolicy: IfNotPresent - command: [sh, -c] - args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] - volumeMounts: - - name: ccs-builder - mountPath: /var/hyperledger/fabric/chaincode/ccs-builder/bin - - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: fabric-config - configMap: - name: fabric-config - - name: ccs-builder - emptyDir: {} - - name: chaincode-config - configMap: - name: chaincode-config - ---- -apiVersion: v1 -kind: Service -metadata: - name: org1-peer1 -spec: - ports: - - name: gossip - port: 7051 - protocol: TCP - - name: chaincode - port: 7052 - protocol: TCP - - name: operations - port: 9443 - protocol: TCP - selector: - app: org1-peer1 \ No newline at end of file diff --git a/test-network-kind/kube/org1-peer2.yaml b/test-network-kind/kube/org1-peer2.yaml deleted file mode 100644 index d43a7405..00000000 --- a/test-network-kind/kube/org1-peer2.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: org1-peer2-config -data: - FABRIC_CFG_PATH: /var/hyperledger/fabric/config - FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" - CORE_PEER_TLS_ENABLED: "true" - CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/server.crt - CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/tls/ca.crt - CORE_PEER_ID: org1-peer2.org1.example.com - CORE_PEER_ADDRESS: org1-peer2:7051 - CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS: org1-peer2:7052 - CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 - # bootstrap peer is the other peer in the same org - CORE_PEER_GOSSIP_BOOTSTRAP: org1-peer1:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT: org1-peer2:7051 - CORE_PEER_LOCALMSPID: Org1MSP - CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/peers/org1-peer2.org1.example.com/msp - CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 - CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org1-peer2.org1.example.com - CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org1-peer2.org1.example.com/snapshots - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: org1-peer2 -spec: - replicas: 1 - selector: - matchLabels: - app: org1-peer2 - template: - metadata: - labels: - app: org1-peer2 - spec: - containers: - - name: main - image: hyperledger/fabric-peer:2.3.2 - imagePullPolicy: Always - envFrom: - - configMapRef: - name: org1-peer2-config - ports: - - containerPort: 7051 - - containerPort: 7052 - - containerPort: 9443 - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: fabric-config - mountPath: /var/hyperledger/fabric/config - - name: ccs-builder - mountPath: /var/hyperledger/fabric/external-chaincode/builder - - # load the external chaincode binaries into the peer image prior to peer launch. - initContainers: - - name: fabric-ccs-builder - # todo: publish this image to docker hub. It's currently read from the kind docker context. - image: hyperledgendary/fabric-ccs-builder - imagePullPolicy: IfNotPresent - command: [sh, -c] - args: ["cp /go/bin/* /podshare"] - volumeMounts: - - name: ccs-builder - mountPath: /podshare - - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: fabric-config - configMap: - name: fabric-config - - name: ccs-builder - emptyDir: {} - ---- -apiVersion: v1 -kind: Service -metadata: - name: org1-peer2 -spec: - ports: - - name: gossip - port: 7051 - protocol: TCP - - name: chaincode - port: 7052 - protocol: TCP - - name: operations - port: 9443 - protocol: TCP - selector: - app: org1-peer2 \ No newline at end of file diff --git a/test-network-kind/kube/org2-peer1.yaml b/test-network-kind/kube/org2-peer1.yaml deleted file mode 100644 index 7cfe6850..00000000 --- a/test-network-kind/kube/org2-peer1.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: org2-peer1-config -data: - FABRIC_CFG_PATH: /var/hyperledger/fabric/config - FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" - CORE_PEER_TLS_ENABLED: "true" - CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/server.crt - CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/tls/ca.crt - CORE_PEER_ID: org2-peer1.org2.example.com - CORE_PEER_ADDRESS: org2-peer1:7051 - CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS: org2-peer1:7052 - CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 - # bootstrap peer is the other peer in the same org - CORE_PEER_GOSSIP_BOOTSTRAP: org2-peer2:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT: org2-peer1:7051 - CORE_PEER_LOCALMSPID: Org2MSP - CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer1.org2.example.com/msp - CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 - CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org2-peer1.org2.example.com - CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org2-peer1.org2.example.com/snapshots - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: org2-peer1 -spec: - replicas: 1 - selector: - matchLabels: - app: org2-peer1 - template: - metadata: - labels: - app: org2-peer1 - spec: - containers: - - name: main - image: hyperledger/fabric-peer:2.3.2 - imagePullPolicy: Always - envFrom: - - configMapRef: - name: org2-peer1-config - ports: - - containerPort: 7051 - - containerPort: 7052 - - containerPort: 9443 - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: fabric-config - mountPath: /var/hyperledger/fabric/config - - name: ccs-builder - mountPath: /var/hyperledger/fabric/external-chaincode/builder - - # load the external chaincode binaries into the peer image prior to peer launch. - initContainers: - - name: fabric-ccs-builder - # todo: publish this image to docker hub. It's currently read from the kind docker context. - image: hyperledgendary/fabric-ccs-builder - imagePullPolicy: IfNotPresent - command: [sh, -c] - args: ["cp /go/bin/* /podshare"] - volumeMounts: - - name: ccs-builder - mountPath: /podshare - - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: fabric-config - configMap: - name: fabric-config - - name: ccs-builder - emptyDir: {} - ---- -apiVersion: v1 -kind: Service -metadata: - name: org2-peer1 -spec: - ports: - - name: gossip - port: 7051 - protocol: TCP - - name: chaincode - port: 7052 - protocol: TCP - - name: operations - port: 9443 - protocol: TCP - selector: - app: org2-peer1 \ No newline at end of file diff --git a/test-network-kind/kube/org2-peer2.yaml b/test-network-kind/kube/org2-peer2.yaml deleted file mode 100644 index 570e2312..00000000 --- a/test-network-kind/kube/org2-peer2.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: org2-peer2-config -data: - FABRIC_CFG_PATH: /var/hyperledger/fabric/config - FABRIC_LOGGING_SPEC: "debug:cauthdsl,policies,msp,grpc,peer.gossip.mcs,gossip,leveldbhelper=info" - CORE_PEER_TLS_ENABLED: "true" - CORE_PEER_TLS_CERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/server.crt - CORE_PEER_TLS_KEY_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/tls/ca.crt - CORE_PEER_ID: org2-peer2.org2.example.com - CORE_PEER_ADDRESS: org2-peer2:7051 - CORE_PEER_LISTENADDRESS: 0.0.0.0:7051 - CORE_PEER_CHAINCODEADDRESS: org2-peer2:7052 - CORE_PEER_CHAINCODELISTENADDRESS: 0.0.0.0:7052 - # bootstrap peer is the other peer in the same org - CORE_PEER_GOSSIP_BOOTSTRAP: org2-peer1:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT: org2-peer2:7051 - CORE_PEER_LOCALMSPID: Org2MSP - CORE_PEER_MSPCONFIGPATH: /var/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/org2-peer2.org2.example.com/msp - CORE_OPERATIONS_LISTENADDRESS: 0.0.0.0:9443 - CORE_PEER_FILESYSTEMPATH: /var/hyperledger/fabric/data/org2-peer2.org2.example.com - CORE_LEDGER_SNAPSHOTS_ROOTDIR: /var/hyperledger/fabric/data/org2-peer2.org2.example.com/snapshots - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: org2-peer2 -spec: - replicas: 1 - selector: - matchLabels: - app: org2-peer2 - template: - metadata: - labels: - app: org2-peer2 - spec: - containers: - - name: main - image: hyperledger/fabric-peer:2.3.2 - imagePullPolicy: Always - envFrom: - - configMapRef: - name: org2-peer2-config - ports: - - containerPort: 7051 - - containerPort: 7052 - - containerPort: 9443 - volumeMounts: - - name: fabric-volume - mountPath: /var/hyperledger/fabric - - name: fabric-config - mountPath: /var/hyperledger/fabric/config - - name: ccs-builder - mountPath: /var/hyperledger/fabric/external-chaincode/builder - - # load the external chaincode binaries into the peer image prior to peer launch. - initContainers: - - name: fabric-ccs-builder - # todo: publish this image to docker hub. It's currently read from the kind docker context. - image: hyperledgendary/fabric-ccs-builder - imagePullPolicy: IfNotPresent - command: [sh, -c] - args: ["cp /go/bin/* /podshare"] - volumeMounts: - - name: ccs-builder - mountPath: /podshare - - volumes: - - name: fabric-volume - persistentVolumeClaim: - claimName: fabric - - name: fabric-config - configMap: - name: fabric-config - - name: ccs-builder - emptyDir: {} - ---- -apiVersion: v1 -kind: Service -metadata: - name: org2-peer2 -spec: - ports: - - name: gossip - port: 7051 - protocol: TCP - - name: chaincode - port: 7052 - protocol: TCP - - name: operations - port: 9443 - protocol: TCP - selector: - app: org2-peer2 \ No newline at end of file diff --git a/test-network-kind/kube/pv-fabric.yaml b/test-network-kind/kube/pv-fabric.yaml deleted file mode 100644 index b77aae53..00000000 --- a/test-network-kind/kube/pv-fabric.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: PersistentVolume -metadata: - name: fabric -spec: - storageClassName: standard - accessModes: - - ReadWriteOnce - capacity: - storage: 2Gi - hostPath: - path: /var/hyperledger/fabric diff --git a/test-network-kind/kube/pvc-fabric.yaml b/test-network-kind/kube/pvc-fabric.yaml deleted file mode 100644 index 861ae55b..00000000 --- a/test-network-kind/kube/pvc-fabric.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: fabric -spec: - volumeName: fabric - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi From 5355fb1b3992fd820f194919ffc96281830b371f Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Mon, 27 Sep 2021 17:09:09 +0530 Subject: [PATCH 014/106] Asset Transfer typescript app using fabric-gateway Signed-off-by: sapthasurendran Added Fabric gateway and removed ca,tslint dependencies Signed-off-by: sapthasurendran eslint migration Signed-off-by: sapthasurendran Added gitignore Signed-off-by: sapthasurendran Transaction Flow Changes Signed-off-by: sapthasurendran Removed serviceClient import,removed outer try catch from main Signed-off-by: sapthasurendran updated fabric-gateway version Signed-off-by: sapthasurendran transaction verification flow change Signed-off-by: sapthasurendran Improved main function readability Signed-off-by: sapthasurendran extra comments Signed-off-by: sapthasurendran Updated fabric-gateway to latest Signed-off-by: sapthasurendran --- .../.eslintrc.json | 45 ++++ .../application-gateway-typescript/.gitignore | 14 + .../package.json | 52 ++++ .../application-gateway-typescript/src/app.ts | 246 ++++++++++++++++++ .../tsconfig.json | 18 ++ ci/scripts/run-test-network-basic.sh | 12 + 6 files changed, 387 insertions(+) create mode 100644 asset-transfer-basic/application-gateway-typescript/.eslintrc.json create mode 100644 asset-transfer-basic/application-gateway-typescript/.gitignore create mode 100644 asset-transfer-basic/application-gateway-typescript/package.json create mode 100644 asset-transfer-basic/application-gateway-typescript/src/app.ts create mode 100644 asset-transfer-basic/application-gateway-typescript/tsconfig.json diff --git a/asset-transfer-basic/application-gateway-typescript/.eslintrc.json b/asset-transfer-basic/application-gateway-typescript/.eslintrc.json new file mode 100644 index 00000000..cc7230a8 --- /dev/null +++ b/asset-transfer-basic/application-gateway-typescript/.eslintrc.json @@ -0,0 +1,45 @@ +{ + "env": { + "node": true, + "es6": true + }, + "root": true, + "ignorePatterns": [ + "dist/" + ], + "extends": [ + "eslint:recommended" + ], + "rules": { + "indent": [ + "error", + 4 + ], + "quotes": [ + "error", + "single" + ] + }, + "overrides": [ + { + "files": [ + "**/*.ts" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "impliedStrict": true + } + }, + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ] + } + ] + } \ No newline at end of file diff --git a/asset-transfer-basic/application-gateway-typescript/.gitignore b/asset-transfer-basic/application-gateway-typescript/.gitignore new file mode 100644 index 00000000..99e5af9f --- /dev/null +++ b/asset-transfer-basic/application-gateway-typescript/.gitignore @@ -0,0 +1,14 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + + +# Coverage directory used by tools like istanbul +coverage + +# Dependency directories +node_modules/ +jspm_packages/ + +# Compiled TypeScript files +dist diff --git a/asset-transfer-basic/application-gateway-typescript/package.json b/asset-transfer-basic/application-gateway-typescript/package.json new file mode 100644 index 00000000..d633b8af --- /dev/null +++ b/asset-transfer-basic/application-gateway-typescript/package.json @@ -0,0 +1,52 @@ +{ + "name": "asset-transfer-basic", + "version": "1.0.0", + "description": "Asset Transfer Basic Application implemented in typeScript using fabric-gateway", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "engines": { + "node": ">=12", + "npm": ">=5" + }, + "scripts": { + "lint": "eslint . --ext .ts", + "pretest": "npm run lint", + "start": "npm run build && node dist/app.js", + "build": "tsc", + "build:watch": "tsc -w", + "prepublishOnly": "npm run build" + }, + "engineStrict": true, + "author": "Hyperledger", + "license": "Apache-2.0", + "dependencies": { + "fabric-gateway": "0.1.0-dev.20211006.12" + }, + "devDependencies": { + "@tsconfig/node12": "^1.0.9", + "@typescript-eslint/eslint-plugin": "^4.31.2", + "@typescript-eslint/parser": "^4.31.2", + "eslint": "^7.32.0", + "typescript": "^3.1.6" + }, + "nyc": { + "extension": [ + ".ts", + ".tsx" + ], + "exclude": [ + "coverage/**", + "dist/**" + ], + "reporter": [ + "text-summary", + "html" + ], + "all": true, + "check-coverage": true, + "statements": 100, + "branches": 100, + "functions": 100, + "lines": 100 + } +} diff --git a/asset-transfer-basic/application-gateway-typescript/src/app.ts b/asset-transfer-basic/application-gateway-typescript/src/app.ts new file mode 100644 index 00000000..0664ee42 --- /dev/null +++ b/asset-transfer-basic/application-gateway-typescript/src/app.ts @@ -0,0 +1,246 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as grpc from '@grpc/grpc-js'; +import * as crypto from 'crypto'; +import { connect, Identity, Signer, signers ,Contract} from 'fabric-gateway'; +import { promises as fs } from 'fs'; +import * as path from 'path'; + +const channelName = 'mychannel'; +const chaincodeName = 'basic'; +const mspId = 'Org1MSP'; + +// path to crypto materials +const cryptoPath = path.resolve( + __dirname, + '..', + '..', + '..', + 'test-network', + 'organizations', + 'peerOrganizations', + 'org1.example.com', +); + +//path to user private key directory +const keyDirectoryPath = path.resolve( + cryptoPath, + 'users', + 'User1@org1.example.com', + 'msp', + 'keystore' +); +//path to user certificate +const certPath = path.resolve( + cryptoPath, + 'users', + 'User1@org1.example.com', + 'msp', + 'signcerts', + 'cert.pem', +); +//path to peer tls certificate +const tlsCertPath = path.resolve( + cryptoPath, + 'peers', + 'peer0.org1.example.com', + 'tls', + 'ca.crt', +); + +//Gateway peer endpoint +const peerEndpoint = 'localhost:7051'; + +// pre-requisites: +// - fabric-sample two organization test-network setup with two peers and ordering service and and 2 certificate authorities +// ===> from directory /fabric-samples/test-network +// ./network.sh up createChannel +// - Use any of the asset-transfer-basic chaincodes deployed on the channel "mychannel" +// with the chaincode name of "basic". The following deploy command will package, +// install, approve, and commit the javascript chaincode, all the actions it takes +// to deploy a chaincode to a channel. +// ===> from directory /fabric-samples/test-network +// ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript +// - Be sure that node.js is installed +// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript +// node -v +// - npm installed code dependencies +// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript +// npm install +// - to run this test application +// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript +// npm start + +/** + * A test application to show basic queries operations with any of the asset-transfer-basic chaincodes + * -- How to submit a transaction + * -- How to query and check the results + * + * To see the SDK workings, try setting the logging to show on the console before running + * export HFC_LOGGING='{"debug":"console"}' + */ + +async function main():Promise { + + // The gRPC client connection should be shared by all Gateway connections to this endpoint + const client = await newGrpcConnection(); + + const gateway = connect({ + client, + identity: await newIdentity(), + signer: await newSigner(), + }); + + try { + + // Build a network instance based on the channel where the smart contract is deployed + const network = gateway.getNetwork(channelName); + + // Get the contract from the network. + const contract = network.getContract(chaincodeName); + + // Initialize a set of asset data on the channel using the chaincode 'InitLedger' function. + await initLedger(contract); + + //Return all the current assets on the ledger. + await getAllAssets(contract); + + //Create new asset on the ledger. + await createAsset(contract); + + //Update an existing asset asynchronously. + await updateAssetAsync(contract); + + //Get the asset details by assetID + await readAssetByID(contract); + + //Update an asset which does not exist. + await updateNonExistentAsset(contract) + + } finally { + gateway.close(); + client.close(); + } + +} + +main().catch(error => console.error('******** FAILED to run the application:', error)); + +async function newGrpcConnection(): Promise { + const tlsRootCert = await fs.readFile(tlsCertPath); + const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); + const GrpcClient = grpc.makeGenericClientConstructor({}, ''); + return new GrpcClient(peerEndpoint, tlsCredentials, { + 'grpc.ssl_target_name_override': 'peer0.org1.example.com', + }); +} + +async function newIdentity(): Promise { + const credentials = await fs.readFile(certPath); + return { mspId, credentials }; +} + +async function newSigner(): Promise { + const files = await fs.readdir(keyDirectoryPath); + const privateKeyPem = await fs.readFile(path.resolve(keyDirectoryPath,files[0])); + const privateKey = crypto.createPrivateKey(privateKeyPem); + return signers.newPrivateKeySigner(privateKey); +} + + +async function initLedger(contract:Contract):Promise { + // This type of transaction would only be run once by an application the first time it was started after it + // deployed the first time. Any updates to the chaincode deployed later would likely not need to run + // an "init" type function. + + console.log( + '\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger', + ); + + // Submit a transaction, blocking until the transaction has been committed on the ledger + await contract.submitTransaction('InitLedger'); + + console.log('*** Result: committed'); + +} + +async function getAllAssets(contract:Contract):Promise { + console.log( + '\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger', + ); + const result = await contract.evaluateTransaction('GetAllAssets'); + console.log(`*** Result: ${Buffer.from(result).toString()}`); +} + +async function createAsset(contract:Contract):Promise { + console.log( + '\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments', + ); + await contract.submitTransaction( + 'CreateAsset', + 'asset13', + 'yellow', + '5', + 'Tom', + '1300', + ); + console.log('*** Result: committed'); +} + +async function updateAssetAsync(contract:Contract):Promise { + + // Submit transaction asynchronously, blocking until the transaction has been sent to the orderer, and allowing + // this thread to process the chaincode response (e.g. update a UI) without waiting for the commit notification + + const commit = await contract.submitAsync('UpdateAsset', { + arguments: ['asset1', 'blue', '5', 'Tomoko', '400'], + }); + + console.log('*** Waiting for transaction commit'); + + + const status = await commit.getStatus(); + if (!status.successful) { + throw new Error(`Transaction ${status.transactionId} failed to commit with status code ${status.code}`); + } + + console.log('*** Transaction committed successfully'); + +} + +async function readAssetByID(contract:Contract):Promise { + console.log( + '\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes', + ); + const result = await contract.evaluateTransaction('ReadAsset', 'asset1'); + console.log(`*** Result: ${Buffer.from(result).toString()}`); + +} + +async function updateNonExistentAsset(contract:Contract):Promise{ + try { + // How about we try a transaction where the executing chaincode throws an error + // Notice how the submitTransaction will throw an error containing the error thrown by the chaincode + console.log( + '\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error', + ); + await contract.submitTransaction( + 'UpdateAsset', + 'asset70', + 'blue', + '5', + 'Tomoko', + '300', + ); + console.log('******** FAILED to return an error'); + } catch (error) { + console.log(`*** Successfully caught the error: \n ${error}`); + } +} + + + diff --git a/asset-transfer-basic/application-gateway-typescript/tsconfig.json b/asset-transfer-basic/application-gateway-typescript/tsconfig.json new file mode 100644 index 00000000..efc75170 --- /dev/null +++ b/asset-transfer-basic/application-gateway-typescript/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends":"@tsconfig/node12/tsconfig.json", + "compilerOptions": { + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "outDir": "dist", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "noImplicitAny": true + }, + "include": [ + "./src/**/*" + ], + "exclude": [ + "./src/**/*.spec.ts" + ] +} diff --git a/ci/scripts/run-test-network-basic.sh b/ci/scripts/run-test-network-basic.sh index 22f5b8c6..8f78c9e7 100755 --- a/ci/scripts/run-test-network-basic.sh +++ b/ci/scripts/run-test-network-basic.sh @@ -63,6 +63,18 @@ node dist/app.js popd stopNetwork +# Run gateway typescript application +createNetwork +print "Initializing Typescript gateway application" +pushd ../asset-transfer-basic/application-gateway-typescript +npm install +print "Building app.ts" +npm run build +print "Running the output app" +node dist/app.js +popd +stopNetwork + # Run typescript HSM application createNetwork print "Initializing Typescript HSM application" From d81684fa0aabbb4dffa7a092e0638f5965c872cb Mon Sep 17 00:00:00 2001 From: Sam Yuan Date: Mon, 25 Oct 2021 23:02:06 +0800 Subject: [PATCH 015/106] resolve for #512 (#513) Signed-off-by: Sam Yuan --- test-network-k8s/kube/pvc-fabric-org0.yaml | 1 + test-network-k8s/kube/pvc-fabric-org1.yaml | 1 + test-network-k8s/kube/pvc-fabric-org2.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/test-network-k8s/kube/pvc-fabric-org0.yaml b/test-network-k8s/kube/pvc-fabric-org0.yaml index c3d64208..a60c212a 100644 --- a/test-network-k8s/kube/pvc-fabric-org0.yaml +++ b/test-network-k8s/kube/pvc-fabric-org0.yaml @@ -10,6 +10,7 @@ metadata: name: fabric-org0 spec: volumeName: fabric-org0 + storageClassName: standard accessModes: - ReadWriteOnce resources: diff --git a/test-network-k8s/kube/pvc-fabric-org1.yaml b/test-network-k8s/kube/pvc-fabric-org1.yaml index d06bc01c..f98e5d97 100644 --- a/test-network-k8s/kube/pvc-fabric-org1.yaml +++ b/test-network-k8s/kube/pvc-fabric-org1.yaml @@ -10,6 +10,7 @@ metadata: name: fabric-org1 spec: volumeName: fabric-org1 + storageClassName: standard accessModes: - ReadWriteOnce resources: diff --git a/test-network-k8s/kube/pvc-fabric-org2.yaml b/test-network-k8s/kube/pvc-fabric-org2.yaml index 40d2e48f..22ddc072 100644 --- a/test-network-k8s/kube/pvc-fabric-org2.yaml +++ b/test-network-k8s/kube/pvc-fabric-org2.yaml @@ -10,6 +10,7 @@ metadata: name: fabric-org2 spec: volumeName: fabric-org2 + storageClassName: standard accessModes: - ReadWriteOnce resources: From 3ba21b4f118555c123d6e94a1582f49fefb25fb4 Mon Sep 17 00:00:00 2001 From: denyeart Date: Tue, 26 Oct 2021 06:22:42 -0400 Subject: [PATCH 016/106] Fix function comment in asset-transfer-ledger-queries (#502) Fix typo in function comment. Thanks to RobertBetschinger for finding this issue. Signed-off-by: David Enyeart --- .../lib/asset_transfer_ledger_chaincode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js b/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js index 33a1aee3..da83bb58 100644 --- a/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js +++ b/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js @@ -11,7 +11,7 @@ // peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["CreateAsset","asset2","red","50","Tom","150"]}' // peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["CreateAsset","asset3","blue","70","Tom","200"]}' // peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["TransferAsset","asset2","jerry"]}' -// peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["TransferAssetsBasedOnColor","blue","jerry"]}' +// peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["TransferAssetByColor","blue","jerry"]}' // peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["DeleteAsset","asset1"]}' // ==== Query assets ==== @@ -186,7 +186,7 @@ class Chaincode extends Contract { return JSON.stringify(results); } - // TransferAssetBasedOnColor will transfer assets of a given color to a certain new owner. + // TransferAssetByColor will transfer assets of a given color to a certain new owner. // Uses a GetStateByPartialCompositeKey (range query) against color~name 'index'. // Committing peers will re-execute range queries to guarantee that result sets are stable // between endorsement time and commit time. The transaction is invalidated by the From d47b2c286a9bfd0a3e24e749eb86e46e420c8b27 Mon Sep 17 00:00:00 2001 From: Justin Yang <90252834+justin-themedium@users.noreply.github.com> Date: Tue, 26 Oct 2021 19:24:15 +0900 Subject: [PATCH 017/106] test-network: Make the regexp of checking version more strict (#515) Signed-off-by: Justin Yang --- test-network/network.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-network/network.sh b/test-network/network.sh index 2b09f79e..17c91ff3 100755 --- a/test-network/network.sh +++ b/test-network/network.sh @@ -53,8 +53,8 @@ function checkPrereqs() { fi # use the fabric tools container to see if the samples and binaries match your # docker images - LOCAL_VERSION=$(peer version | sed -ne 's/ Version: //p') - DOCKER_IMAGE_VERSION=$(docker run --rm hyperledger/fabric-tools:latest peer version | sed -ne 's/ Version: //p' | head -1) + LOCAL_VERSION=$(peer version | sed -ne 's/^ Version: //p') + DOCKER_IMAGE_VERSION=$(docker run --rm hyperledger/fabric-tools:latest peer version | sed -ne 's/^ Version: //p') infoln "LOCAL_VERSION=$LOCAL_VERSION" infoln "DOCKER_IMAGE_VERSION=$DOCKER_IMAGE_VERSION" From 1b1ef046c176d26473d1f16312ca1edc7c37f92d Mon Sep 17 00:00:00 2001 From: jkneubuh <86427252+jkneubuh@users.noreply.github.com> Date: Wed, 27 Oct 2021 11:24:26 -0400 Subject: [PATCH 018/106] Allow overrides of the docker registry for fabric images (#518) Signed-off-by: Josh Kneubuhl --- .../kube/org0/org0-admin-cli.yaml | 2 +- test-network-k8s/kube/org0/org0-ecert-ca.yaml | 2 +- test-network-k8s/kube/org0/org0-orderer1.yaml | 4 ++-- test-network-k8s/kube/org0/org0-orderer2.yaml | 4 ++-- test-network-k8s/kube/org0/org0-orderer3.yaml | 4 ++-- test-network-k8s/kube/org0/org0-tls-ca.yaml | 2 +- .../kube/org1/org1-admin-cli.yaml | 4 ++-- test-network-k8s/kube/org1/org1-ecert-ca.yaml | 2 +- test-network-k8s/kube/org1/org1-peer1.yaml | 6 ++--- test-network-k8s/kube/org1/org1-peer2.yaml | 4 ++-- test-network-k8s/kube/org1/org1-tls-ca.yaml | 2 +- .../kube/org2/org2-admin-cli.yaml | 2 +- test-network-k8s/kube/org2/org2-ecert-ca.yaml | 2 +- test-network-k8s/kube/org2/org2-peer1.yaml | 2 +- test-network-k8s/kube/org2/org2-peer2.yaml | 2 +- test-network-k8s/kube/org2/org2-tls-ca.yaml | 2 +- test-network-k8s/network | 8 +++---- test-network-k8s/scripts/channel.sh | 6 ++--- test-network-k8s/scripts/fabric_CAs.sh | 20 ++++++++++++----- test-network-k8s/scripts/kind.sh | 22 +++++-------------- test-network-k8s/scripts/test_network.sh | 5 ++++- 21 files changed, 53 insertions(+), 54 deletions(-) diff --git a/test-network-k8s/kube/org0/org0-admin-cli.yaml b/test-network-k8s/kube/org0/org0-admin-cli.yaml index c7bf84bb..85c81343 100644 --- a/test-network-k8s/kube/org0/org0-admin-cli.yaml +++ b/test-network-k8s/kube/org0/org0-admin-cli.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-tools:{{FABRIC_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent env: - name: FABRIC_CFG_PATH diff --git a/test-network-k8s/kube/org0/org0-ecert-ca.yaml b/test-network-k8s/kube/org0/org0-ecert-ca.yaml index 40c2edeb..1e7e8299 100644 --- a/test-network-k8s/kube/org0/org0-ecert-ca.yaml +++ b/test-network-k8s/kube/org0/org0-ecert-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-ca:1.5.2 + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org0-ecert-ca" diff --git a/test-network-k8s/kube/org0/org0-orderer1.yaml b/test-network-k8s/kube/org0/org0-orderer1.yaml index a37b274d..f3e06d1b 100644 --- a/test-network-k8s/kube/org0/org0-orderer1.yaml +++ b/test-network-k8s/kube/org0/org0-orderer1.yaml @@ -43,8 +43,8 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-orderer:{{FABRIC_VERSION}} - imagePullPolicy: IfNotPresent + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: Always envFrom: - configMapRef: name: org0-orderer1-env diff --git a/test-network-k8s/kube/org0/org0-orderer2.yaml b/test-network-k8s/kube/org0/org0-orderer2.yaml index 0070fda9..f9a1f6eb 100644 --- a/test-network-k8s/kube/org0/org0-orderer2.yaml +++ b/test-network-k8s/kube/org0/org0-orderer2.yaml @@ -43,8 +43,8 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-orderer:{{FABRIC_VERSION}} - imagePullPolicy: IfNotPresent + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: Always envFrom: - configMapRef: name: org0-orderer2-env diff --git a/test-network-k8s/kube/org0/org0-orderer3.yaml b/test-network-k8s/kube/org0/org0-orderer3.yaml index 4db6edbf..ba913d2d 100644 --- a/test-network-k8s/kube/org0/org0-orderer3.yaml +++ b/test-network-k8s/kube/org0/org0-orderer3.yaml @@ -43,8 +43,8 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-orderer:{{FABRIC_VERSION}} - imagePullPolicy: IfNotPresent + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: Always envFrom: - configMapRef: name: org0-orderer3-env diff --git a/test-network-k8s/kube/org0/org0-tls-ca.yaml b/test-network-k8s/kube/org0/org0-tls-ca.yaml index 179d9c44..a28649df 100644 --- a/test-network-k8s/kube/org0/org0-tls-ca.yaml +++ b/test-network-k8s/kube/org0/org0-tls-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-ca:1.5.2 + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org0-tls-ca" diff --git a/test-network-k8s/kube/org1/org1-admin-cli.yaml b/test-network-k8s/kube/org1/org1-admin-cli.yaml index 665f3595..5e4f74b9 100644 --- a/test-network-k8s/kube/org1/org1-admin-cli.yaml +++ b/test-network-k8s/kube/org1/org1-admin-cli.yaml @@ -20,8 +20,8 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-tools:{{FABRIC_VERSION}} - imagePullPolicy: IfNotPresent + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} + imagePullPolicy: Always env: - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric/config diff --git a/test-network-k8s/kube/org1/org1-ecert-ca.yaml b/test-network-k8s/kube/org1/org1-ecert-ca.yaml index e3da8d11..a0c4994a 100644 --- a/test-network-k8s/kube/org1/org1-ecert-ca.yaml +++ b/test-network-k8s/kube/org1/org1-ecert-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-ca:1.5.2 + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org1-ecert-ca" diff --git a/test-network-k8s/kube/org1/org1-peer1.yaml b/test-network-k8s/kube/org1/org1-peer1.yaml index 0f756a40..c913a535 100644 --- a/test-network-k8s/kube/org1/org1-peer1.yaml +++ b/test-network-k8s/kube/org1/org1-peer1.yaml @@ -46,8 +46,8 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-peer:{{FABRIC_VERSION}} - imagePullPolicy: IfNotPresent + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + imagePullPolicy: Always envFrom: - configMapRef: name: org1-peer1-config @@ -67,7 +67,7 @@ spec: initContainers: - name: fabric-ccs-builder image: ghcr.io/hyperledgendary/fabric-ccs-builder - imagePullPolicy: IfNotPresent + imagePullPolicy: Always command: [sh, -c] args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] volumeMounts: diff --git a/test-network-k8s/kube/org1/org1-peer2.yaml b/test-network-k8s/kube/org1/org1-peer2.yaml index 152c950e..8c2f85a7 100644 --- a/test-network-k8s/kube/org1/org1-peer2.yaml +++ b/test-network-k8s/kube/org1/org1-peer2.yaml @@ -46,8 +46,8 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-peer:{{FABRIC_VERSION}} - imagePullPolicy: IfNotPresent + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + imagePullPolicy: Always envFrom: - configMapRef: name: org1-peer2-config diff --git a/test-network-k8s/kube/org1/org1-tls-ca.yaml b/test-network-k8s/kube/org1/org1-tls-ca.yaml index afedbe4d..71767ff6 100644 --- a/test-network-k8s/kube/org1/org1-tls-ca.yaml +++ b/test-network-k8s/kube/org1/org1-tls-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-ca:1.5.2 + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org1-tls-ca" diff --git a/test-network-k8s/kube/org2/org2-admin-cli.yaml b/test-network-k8s/kube/org2/org2-admin-cli.yaml index be47123a..6839455a 100644 --- a/test-network-k8s/kube/org2/org2-admin-cli.yaml +++ b/test-network-k8s/kube/org2/org2-admin-cli.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-tools:{{FABRIC_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent env: - name: FABRIC_CFG_PATH diff --git a/test-network-k8s/kube/org2/org2-ecert-ca.yaml b/test-network-k8s/kube/org2/org2-ecert-ca.yaml index 56c3350f..f983a5ae 100644 --- a/test-network-k8s/kube/org2/org2-ecert-ca.yaml +++ b/test-network-k8s/kube/org2/org2-ecert-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-ca:1.5.2 + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org2-ecert-ca" diff --git a/test-network-k8s/kube/org2/org2-peer1.yaml b/test-network-k8s/kube/org2/org2-peer1.yaml index 193dd2cc..b77bd70d 100644 --- a/test-network-k8s/kube/org2/org2-peer1.yaml +++ b/test-network-k8s/kube/org2/org2-peer1.yaml @@ -46,7 +46,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-peer:{{FABRIC_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent envFrom: - configMapRef: diff --git a/test-network-k8s/kube/org2/org2-peer2.yaml b/test-network-k8s/kube/org2/org2-peer2.yaml index c0df9b4e..e68363c9 100644 --- a/test-network-k8s/kube/org2/org2-peer2.yaml +++ b/test-network-k8s/kube/org2/org2-peer2.yaml @@ -46,7 +46,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-peer:{{FABRIC_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent envFrom: - configMapRef: diff --git a/test-network-k8s/kube/org2/org2-tls-ca.yaml b/test-network-k8s/kube/org2/org2-tls-ca.yaml index b28a7aa0..c49222e2 100644 --- a/test-network-k8s/kube/org2/org2-tls-ca.yaml +++ b/test-network-k8s/kube/org2/org2-tls-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: hyperledger/fabric-ca:1.5.2 + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org2-tls-ca" diff --git a/test-network-k8s/network b/test-network-k8s/network index ecbef2a3..08df4c98 100755 --- a/test-network-k8s/network +++ b/test-network-k8s/network @@ -15,21 +15,22 @@ set -o errexit # todo: user:pass auth for tls and ecert bootstrap admins. here and in the server-config.yaml # todo: set tls.certfiles= ... arg in deployment env / yaml # todo: refactor chaincode install to support other chaincode routines -# todo: actually compile the chaincode archive, rather than reading a pre-canned one from chaincode/*.tgz (use sha256 to get CC ID) # todo: consider using templates for boilerplate network nodes (orderers, peers, ...) # todo: allow the user to specify the chaincode name (hardcoded as 'basic') both in install and invoke/query # todo: track down a nasty bug whereby the CA service endpoints (kube services) will occasionally reject TCP connections after network down/up. This is patched by introducing a 10s sleep after the deployments are up... # todo: refactor query/invoke to specify chaincode name (-n param) FABRIC_VERSION=${TEST_NETWORK_FABRIC_VERSION:-2.3.2} +FABRIC_CA_VERSION=${TEST_NETWORK_FABRIC_CA_VERSION:-1.5.2} +FABRIC_CONTAINER_REGISTRY=${TEST_NETWORK_FABRIC_CONTAINER_REGISTRY:-hyperledger} NETWORK_NAME=${TEST_NETWORK_NAME:-test-network} CLUSTER_NAME=${TEST_NETWORK_KIND_CLUSTER_NAME:-kind} NS=${TEST_NETWORK_KUBE_NAMESPACE:-${NETWORK_NAME}} CHANNEL_NAME=${TEST_NETWORK_CHANNEL_NAME:-mychannel} LOG_FILE=${TEST_NETWORK_LOG_FILE:-network.log} DEBUG_FILE=${TEST_NETWORK_DEBUG_FILE:-network-debug.log} -CONTAINER_REGISTRY_NAME=${TEST_NETWORK_CONTAINER_REGISTRY_NAME:-kind-registry} -CONTAINER_REGISTRY_PORT=${TEST_NETWORK_CONTAINER_REGISTRY_PORT:-5000} +LOCAL_REGISTRY_NAME=${TEST_NETWORK_LOCAL_REGISTRY_NAME:-kind-registry} +LOCAL_REGISTRY_PORT=${TEST_NETWORK_LOCAL_REGISTRY_PORT:-5000} NGINX_HTTP_PORT=${TEST_NETWORK_INGRESS_HTTP_PORT:-80} NGINX_HTTPS_PORT=${TEST_NETWORK_INGRESS_HTTPS_PORT:-443} CHAINCODE_NAME=${TEST_NETWORK_CHAINCODE_NAME:-asset-transfer-basic} @@ -37,7 +38,6 @@ CHAINCODE_IMAGE=${TEST_NETWORK_CHAINCODE_IMAGE:-ghcr.io/hyperledgendary/fabric-c CHAINCODE_LABEL=${TEST_NETWORK_CHAINCODE_LABEL:-basic_1.0} # todo: more complicated config, as these bleed into the yaml descriptors (sed? kustomize? helm (no)? tkn? ansible?...) or other script locations -FABRIC_CA_VERSION=1.5.2 TLSADMIN_AUTH=tlsadmin:tlsadminpw RCAADMIN_AUTH=rcaadmin:rcaadminpw diff --git a/test-network-k8s/scripts/channel.sh b/test-network-k8s/scripts/channel.sh index f8a79555..5aa3158f 100755 --- a/test-network-k8s/scripts/channel.sh +++ b/test-network-k8s/scripts/channel.sh @@ -69,9 +69,9 @@ function aggregate_channel_MSP() { function launch_admin_CLIs() { push_fn "Launching admin CLIs" - cat kube/org0/org0-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - - cat kube/org1/org1-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - - cat kube/org2/org2-admin-cli.yaml | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - + launch kube/org0/org0-admin-cli.yaml + launch kube/org1/org1-admin-cli.yaml + launch kube/org2/org2-admin-cli.yaml kubectl -n $NS rollout status deploy/org0-admin-cli kubectl -n $NS rollout status deploy/org1-admin-cli diff --git a/test-network-k8s/scripts/fabric_CAs.sh b/test-network-k8s/scripts/fabric_CAs.sh index 6ec4708a..a0ee760f 100755 --- a/test-network-k8s/scripts/fabric_CAs.sh +++ b/test-network-k8s/scripts/fabric_CAs.sh @@ -5,12 +5,20 @@ # SPDX-License-Identifier: Apache-2.0 # +function launch_CA() { + local yaml=$1 + cat ${yaml} \ + | sed 's,{{FABRIC_CONTAINER_REGISTRY}},'${FABRIC_CONTAINER_REGISTRY}',g' \ + | sed 's,{{FABRIC_CA_VERSION}},'${FABRIC_CA_VERSION}',g' \ + | kubectl -n $NS apply -f - +} + function launch_TLS_CAs() { push_fn "Launching TLS CAs" - kubectl -n $NS apply -f kube/org0/org0-tls-ca.yaml - kubectl -n $NS apply -f kube/org1/org1-tls-ca.yaml - kubectl -n $NS apply -f kube/org2/org2-tls-ca.yaml + launch_CA kube/org0/org0-tls-ca.yaml + launch_CA kube/org1/org1-tls-ca.yaml + launch_CA kube/org2/org2-tls-ca.yaml kubectl -n $NS rollout status deploy/org0-tls-ca kubectl -n $NS rollout status deploy/org1-tls-ca @@ -25,9 +33,9 @@ function launch_TLS_CAs() { function launch_ECert_CAs() { push_fn "Launching ECert CAs" - kubectl -n $NS apply -f kube/org0/org0-ecert-ca.yaml - kubectl -n $NS apply -f kube/org1/org1-ecert-ca.yaml - kubectl -n $NS apply -f kube/org2/org2-ecert-ca.yaml + launch_CA kube/org0/org0-ecert-ca.yaml + launch_CA kube/org1/org1-ecert-ca.yaml + launch_CA kube/org2/org2-ecert-ca.yaml kubectl -n $NS rollout status deploy/org0-ecert-ca kubectl -n $NS rollout status deploy/org1-ecert-ca diff --git a/test-network-k8s/scripts/kind.sh b/test-network-k8s/scripts/kind.sh index 1784204d..0d4db35d 100755 --- a/test-network-k8s/scripts/kind.sh +++ b/test-network-k8s/scripts/kind.sh @@ -5,17 +5,6 @@ # SPDX-License-Identifier: Apache-2.0 # -function pull_docker_images() { - push_fn "Pulling docker images for Fabric ${FABRIC_VERSION}" - - docker pull hyperledger/fabric-ca:$FABRIC_CA_VERSION - docker pull hyperledger/fabric-orderer:$FABRIC_VERSION - docker pull hyperledger/fabric-peer:$FABRIC_VERSION - docker pull hyperledger/fabric-tools:$FABRIC_VERSION - - pop_fn -} - function apply_nginx_ingress() { push_fn "Launching Nginx ingress controller" @@ -34,8 +23,8 @@ function kind_create() { # todo: always delete? Maybe return no-op if the cluster already exists? kind delete cluster --name $CLUSTER_NAME - local reg_name=${CONTAINER_REGISTRY_NAME} - local reg_port=${CONTAINER_REGISTRY_PORT} + local reg_name=${LOCAL_REGISTRY_NAME} + local reg_port=${LOCAL_REGISTRY_PORT} local ingress_http_port=${NGINX_HTTP_PORT} local ingress_https_port=${NGINX_HTTPS_PORT} @@ -71,11 +60,11 @@ EOF } function launch_docker_registry() { - push_fn "Launching container registry \"${CONTAINER_REGISTRY_NAME}\" at localhost:${CONTAINER_REGISTRY_PORT}" + push_fn "Launching container registry \"${LOCAL_REGISTRY_NAME}\" at localhost:${LOCAL_REGISTRY_PORT}" # create registry container unless it already exists - local reg_name=${CONTAINER_REGISTRY_NAME} - local reg_port=${CONTAINER_REGISTRY_PORT} + local reg_name=${LOCAL_REGISTRY_NAME} + local reg_port=${LOCAL_REGISTRY_PORT} running="$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" if [ "${running}" != 'true' ]; then @@ -123,7 +112,6 @@ function kind_init() { # todo: how to pass this through to push_fn ? set -o errexit - pull_docker_images kind_create apply_nginx_ingress launch_docker_registry diff --git a/test-network-k8s/scripts/test_network.sh b/test-network-k8s/scripts/test_network.sh index a0a0c87a..05279609 100755 --- a/test-network-k8s/scripts/test_network.sh +++ b/test-network-k8s/scripts/test_network.sh @@ -10,7 +10,10 @@ function launch() { local yaml=$1 - cat ${yaml} | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' | kubectl -n $NS apply -f - + cat ${yaml} \ + | sed 's,{{FABRIC_CONTAINER_REGISTRY}},'${FABRIC_CONTAINER_REGISTRY}',g' \ + | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' \ + | kubectl -n $NS apply -f - } function launch_orderers() { From cc8123bdc5b3f23cff2afb5a82fcc8a1db39e8fd Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Fri, 22 Oct 2021 10:23:23 +0100 Subject: [PATCH 019/106] Remove temporary buildfiles Signed-off-by: Matthew B White --- .gitignore | 4 ++++ .../application-java/.settings/org.eclipse.jdt.core.prefs | 6 ------ .../.settings/org.eclipse.buildship.core.prefs | 2 -- 3 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 commercial-paper/organization/magnetocorp/application-java/.settings/org.eclipse.jdt.core.prefs delete mode 100644 commercial-paper/organization/magnetocorp/contract-java/.settings/org.eclipse.buildship.core.prefs diff --git a/.gitignore b/.gitignore index 63eb90ca..9e2d7d0e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,7 @@ node_modules/ build package-lock.json external-chaincode/ + +# Eclipse +.classpath +.settings diff --git a/commercial-paper/organization/magnetocorp/application-java/.settings/org.eclipse.jdt.core.prefs b/commercial-paper/organization/magnetocorp/application-java/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index b8947ec6..00000000 --- a/commercial-paper/organization/magnetocorp/application-java/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,6 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/commercial-paper/organization/magnetocorp/contract-java/.settings/org.eclipse.buildship.core.prefs b/commercial-paper/organization/magnetocorp/contract-java/.settings/org.eclipse.buildship.core.prefs deleted file mode 100644 index e8895216..00000000 --- a/commercial-paper/organization/magnetocorp/contract-java/.settings/org.eclipse.buildship.core.prefs +++ /dev/null @@ -1,2 +0,0 @@ -connection.project.dir= -eclipse.preferences.version=1 From 337584045d1a8c1ac88ae2fed68cdf5bc62e960a Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Thu, 28 Oct 2021 10:28:16 +0100 Subject: [PATCH 020/106] Updated logging - updated the logging for the application command; wasn't very good - added some information to the help option. the current settings useful if you're not sure what you've set Signed-off-by: Matthew B White --- test-network-k8s/network | 35 +++++++++++++++++-- .../scripts/application_connection.sh | 31 ++++++++++++---- test-network-k8s/scripts/utils.sh | 4 +++ 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/test-network-k8s/network b/test-network-k8s/network index 08df4c98..447f2d48 100755 --- a/test-network-k8s/network +++ b/test-network-k8s/network @@ -42,6 +42,33 @@ TLSADMIN_AUTH=tlsadmin:tlsadminpw RCAADMIN_AUTH=rcaadmin:rcaadminpw function print_help() { + log + log "--- Fabric Information" + log "Fabric Version is \t ${FABRIC_VERSION}" + log "Fabric CA Version is \t ${FABRIC_CA_VERSION}" + log "Container Registry is \t ${FABRIC_CONTAINER_REGISTRY}" + log "Network name is \t ${NETWORK_NAME}" + log "Channel name is \t ${CHANNEL_NAME}" + log + log "--- Targetted Chaincode Information" + log "Chaincode name is \t ${CHAINCODE_NAME}" + log "Chaincode image is \t ${CHAINCODE_IMAGE}" + log "Chaincode lavel is \t ${CHAINCODE_LABEL}" + log + log "--- Cluster Information" + log "Cluster name is \t ${CLUSTER_NAME}" + log "Cluster namespace is \t ${NS}" + log "Local Registry is \t ${LOCAL_REGISTRY_NAME}" + log "Local Registry port is \t ${LOCAL_REGISTRY_PORT}" + log "nginx http port is \t ${NGINX_HTTP_PORT}" + log "nginx https port is \t ${NGINX_HTTP2_PORT}" + log + log "--- Script Information" + log "Log file written to \t ${LOG_FILE}" + log "Debug log written to \t ${DEBUG_FILE}" + log + + echo todo: help output, parse mode, flags, env, etc. } @@ -59,6 +86,9 @@ function print_help() { # check for kind, kubectl, etc. check_prereqs +# Initialize the logging system - control output to 'network.log' and everything else to 'network-debug.log' +logging_init + ## Parse mode if [[ $# -lt 1 ]] ; then print_help @@ -68,8 +98,7 @@ else shift fi -# Initialize the logging system - control output to 'network.log' and everything else to 'network-debug.log' -logging_init + if [ "${MODE}" == "kind" ]; then log "Initializing KIND cluster \"${CLUSTER_NAME}\":" @@ -148,7 +177,7 @@ elif [ "${MODE}" == "rest-easy" ]; then elif [ "${MODE}" == "application" ]; then log "Getting application connection information:" application_connection - log "🏁 - Output in...xxx" + log "🏁 - Application connection information ready." else print_help diff --git a/test-network-k8s/scripts/application_connection.sh b/test-network-k8s/scripts/application_connection.sh index 3f73dd20..9563b128 100755 --- a/test-network-k8s/scripts/application_connection.sh +++ b/test-network-k8s/scripts/application_connection.sh @@ -57,7 +57,11 @@ function construct_application_configmap() { ca_pem=build/msp/organizations/peerOrganizations/org2.example.com/msp/cacerts/org2-ecert-ca.pem echo "$(json_ccp 2 $peer_pem $ca_pem)" > build/application/gateways/org2_ccp.json - + + pop_fn + + push_fn "Getting Application Identities" + local cert=build/msp/organizations/peerOrganizations/org1.example.com/users/Admin\@org1.example.com/msp/signcerts/cert.pem local pk=build/msp/organizations/peerOrganizations/org1.example.com/users/Admin\@org1.example.com/msp/keystore/server.key @@ -68,14 +72,24 @@ function construct_application_configmap() { echo "$(app_id Org2MSP $cert $pk)" > build/application/wallet/appuser_org2.id - kubectl -n $NS delete configmap app-fabric-tls-v1-map || log "app-fabric-tls-v1-map not present" + pop_fn + + push_fn "Creating ConfigMap \"app-fabric-tls-v1-map\" with TLS certificates for the application" + kubectl -n $NS delete configmap app-fabric-tls-v1-map || true kubectl -n $NS create configmap app-fabric-tls-v1-map --from-file=./build/msp/organizations/peerOrganizations/org1.example.com/msp/tlscacerts + pop_fn - kubectl -n $NS delete configmap app-fabric-ids-v1-map || log "app-fabric-id-v1-map not present" + push_fn "Creating ConfigMap \"app-fabric-ids-v1-map\" with identities for the application" + kubectl -n $NS delete configmap app-fabric-ids-v1-map || true kubectl -n $NS create configmap app-fabric-ids-v1-map --from-file=./build/application/wallet + pop_fn - kubectl -n $NS delete configmap app-fabric-ccp-v1-map || log "app-fabric-id-v1-map not present" + push_fn "Creating ConfigMap \"app-fabric-ccp-v1-map\" with ConnectionProfile for the application" + kubectl -n $NS delete configmap app-fabric-ccp-v1-map || true kubectl -n $NS create configmap app-fabric-ccp-v1-map --from-file=./build/application/gateways + pop_fn + + push_fn "Creating ConfigMap \"app-fabric-org1-v1-map\" with Organization 1 information for the application" cat < build/app-fabric-org1-v1-map.yaml apiVersion: v1 @@ -104,11 +118,16 @@ function application_connection() { construct_application_configmap - log "" +log + log "For k8s applications:" log "Config Maps created for the application" log "To deploy your application updated the image name and issue these commands" log "" log "kubectl -n $NS apply -f kube/application-deployment.yaml" log "kubectl -n $NS rollout status deploy/application-deployment" - + log + log "For non-k8s applications:" + log "ConnectionPrfiles are in ${PWD}/build/application/gateways" + log "Identities are in ${PWD}/build/application/wallets" + log } \ No newline at end of file diff --git a/test-network-k8s/scripts/utils.sh b/test-network-k8s/scripts/utils.sh index a1631aa4..b00802e3 100644 --- a/test-network-k8s/scripts/utils.sh +++ b/test-network-k8s/scripts/utils.sh @@ -17,6 +17,10 @@ function logging_init() { # Send stdout and stderr from child programs to the debug log file exec 1>>${DEBUG_FILE} 2>>${DEBUG_FILE} + + # There can be a race between the tail starting and the next log statement + # write nothing to the file to kill a (very small) bit of time + echo -ne >>${LOG_FILE} } function exit_fn() { From 6627cd6d6544f53fff1171f6be7d58a0686395ee Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Thu, 28 Oct 2021 15:07:42 +0100 Subject: [PATCH 021/106] review cmts Signed-off-by: Matthew B White --- test-network-k8s/network | 34 +++++++++++++++---------------- test-network-k8s/scripts/utils.sh | 3 +-- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/test-network-k8s/network b/test-network-k8s/network index 447f2d48..a1008235 100755 --- a/test-network-k8s/network +++ b/test-network-k8s/network @@ -44,28 +44,28 @@ RCAADMIN_AUTH=rcaadmin:rcaadminpw function print_help() { log log "--- Fabric Information" - log "Fabric Version is \t ${FABRIC_VERSION}" - log "Fabric CA Version is \t ${FABRIC_CA_VERSION}" - log "Container Registry is \t ${FABRIC_CONTAINER_REGISTRY}" - log "Network name is \t ${NETWORK_NAME}" - log "Channel name is \t ${CHANNEL_NAME}" + log "Fabric Version \t\t: ${FABRIC_VERSION}" + log "Fabric CA Version \t: ${FABRIC_CA_VERSION}" + log "Container Registry \t: ${FABRIC_CONTAINER_REGISTRY}" + log "Network name \t\t: ${NETWORK_NAME}" + log "Channel name \t\t: ${CHANNEL_NAME}" log - log "--- Targetted Chaincode Information" - log "Chaincode name is \t ${CHAINCODE_NAME}" - log "Chaincode image is \t ${CHAINCODE_IMAGE}" - log "Chaincode lavel is \t ${CHAINCODE_LABEL}" + log "--- Chaincode Information" + log "Chaincode name \t\t: ${CHAINCODE_NAME}" + log "Chaincode image \t: ${CHAINCODE_IMAGE}" + log "Chaincode label \t: ${CHAINCODE_LABEL}" log log "--- Cluster Information" - log "Cluster name is \t ${CLUSTER_NAME}" - log "Cluster namespace is \t ${NS}" - log "Local Registry is \t ${LOCAL_REGISTRY_NAME}" - log "Local Registry port is \t ${LOCAL_REGISTRY_PORT}" - log "nginx http port is \t ${NGINX_HTTP_PORT}" - log "nginx https port is \t ${NGINX_HTTP2_PORT}" + log "Cluster name \t\t: ${CLUSTER_NAME}" + log "Cluster namespace \t: ${NS}" + log "Local Registry \t\t: ${LOCAL_REGISTRY_NAME}" + log "Local Registry port \t: ${LOCAL_REGISTRY_PORT}" + log "nginx http port \t: ${NGINX_HTTP_PORT}" + log "nginx https port \t: ${NGINX_HTTPS_PORT}" log log "--- Script Information" - log "Log file written to \t ${LOG_FILE}" - log "Debug log written to \t ${DEBUG_FILE}" + log "Log file \t\t: ${LOG_FILE}" + log "Debug log file \t\t: ${DEBUG_FILE}" log diff --git a/test-network-k8s/scripts/utils.sh b/test-network-k8s/scripts/utils.sh index b00802e3..b777865c 100644 --- a/test-network-k8s/scripts/utils.sh +++ b/test-network-k8s/scripts/utils.sh @@ -19,8 +19,7 @@ function logging_init() { exec 1>>${DEBUG_FILE} 2>>${DEBUG_FILE} # There can be a race between the tail starting and the next log statement - # write nothing to the file to kill a (very small) bit of time - echo -ne >>${LOG_FILE} + sleep 0.5 } function exit_fn() { From 0a1efc45cd0c2a93a0023c2e30eccb5bee7acd2c Mon Sep 17 00:00:00 2001 From: Sam Yuan Date: Tue, 2 Nov 2021 23:43:31 +0800 Subject: [PATCH 022/106] nit fixs (#519) 1. busybox latest image tag 2. pull images with more images 3. load images to kind cluster at local Signed-off-by: Sam Yuan --- test-network-k8s/docs/TEST_NETWORK.md | 2 +- .../kube/job-scrub-fabric-volumes.yaml | 2 +- .../kube/org0/org0-admin-cli.yaml | 2 +- test-network-k8s/kube/org0/org0-ecert-ca.yaml | 2 +- test-network-k8s/kube/org0/org0-orderer1.yaml | 2 +- test-network-k8s/kube/org0/org0-orderer2.yaml | 2 +- test-network-k8s/kube/org0/org0-orderer3.yaml | 2 +- test-network-k8s/kube/org0/org0-tls-ca.yaml | 2 +- .../kube/org1/org1-admin-cli.yaml | 2 +- test-network-k8s/kube/org1/org1-ecert-ca.yaml | 2 +- test-network-k8s/kube/org1/org1-peer1.yaml | 4 +- test-network-k8s/kube/org1/org1-peer2.yaml | 2 +- test-network-k8s/kube/org1/org1-tls-ca.yaml | 2 +- .../kube/org2/org2-admin-cli.yaml | 2 +- test-network-k8s/kube/org2/org2-ecert-ca.yaml | 2 +- test-network-k8s/kube/org2/org2-peer1.yaml | 4 +- test-network-k8s/kube/org2/org2-peer2.yaml | 2 +- test-network-k8s/kube/org2/org2-tls-ca.yaml | 2 +- test-network-k8s/network | 3 +- test-network-k8s/scripts/fabric_CAs.sh | 2 +- test-network-k8s/scripts/kind.sh | 40 ++++++++++++++++--- test-network-k8s/scripts/test_network.sh | 5 ++- 22 files changed, 62 insertions(+), 28 deletions(-) diff --git a/test-network-k8s/docs/TEST_NETWORK.md b/test-network-k8s/docs/TEST_NETWORK.md index 2a97728e..6f534114 100644 --- a/test-network-k8s/docs/TEST_NETWORK.md +++ b/test-network-k8s/docs/TEST_NETWORK.md @@ -135,7 +135,7 @@ from a public container registry, copying the external builders into the target ```yaml initContainers: - name: fabric-ccs-builder - image: ghcr.io/hyperledgendary/fabric-ccs-builder + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ccs-builder command: [sh, -c] args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] volumeMounts: diff --git a/test-network-k8s/kube/job-scrub-fabric-volumes.yaml b/test-network-k8s/kube/job-scrub-fabric-volumes.yaml index 2acddc92..ce2b4f48 100644 --- a/test-network-k8s/kube/job-scrub-fabric-volumes.yaml +++ b/test-network-k8s/kube/job-scrub-fabric-volumes.yaml @@ -18,7 +18,7 @@ spec: restartPolicy: "Never" containers: - name: main - image: busybox + image: busybox:latest command: - sh - -c diff --git a/test-network-k8s/kube/org0/org0-admin-cli.yaml b/test-network-k8s/kube/org0/org0-admin-cli.yaml index 85c81343..ad32646b 100644 --- a/test-network-k8s/kube/org0/org0-admin-cli.yaml +++ b/test-network-k8s/kube/org0/org0-admin-cli.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent env: - name: FABRIC_CFG_PATH diff --git a/test-network-k8s/kube/org0/org0-ecert-ca.yaml b/test-network-k8s/kube/org0/org0-ecert-ca.yaml index 1e7e8299..094e9671 100644 --- a/test-network-k8s/kube/org0/org0-ecert-ca.yaml +++ b/test-network-k8s/kube/org0/org0-ecert-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org0-ecert-ca" diff --git a/test-network-k8s/kube/org0/org0-orderer1.yaml b/test-network-k8s/kube/org0/org0-orderer1.yaml index f3e06d1b..f5c3c702 100644 --- a/test-network-k8s/kube/org0/org0-orderer1.yaml +++ b/test-network-k8s/kube/org0/org0-orderer1.yaml @@ -43,7 +43,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} imagePullPolicy: Always envFrom: - configMapRef: diff --git a/test-network-k8s/kube/org0/org0-orderer2.yaml b/test-network-k8s/kube/org0/org0-orderer2.yaml index f9a1f6eb..9a7188f9 100644 --- a/test-network-k8s/kube/org0/org0-orderer2.yaml +++ b/test-network-k8s/kube/org0/org0-orderer2.yaml @@ -43,7 +43,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} imagePullPolicy: Always envFrom: - configMapRef: diff --git a/test-network-k8s/kube/org0/org0-orderer3.yaml b/test-network-k8s/kube/org0/org0-orderer3.yaml index ba913d2d..b9aa1431 100644 --- a/test-network-k8s/kube/org0/org0-orderer3.yaml +++ b/test-network-k8s/kube/org0/org0-orderer3.yaml @@ -43,7 +43,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} imagePullPolicy: Always envFrom: - configMapRef: diff --git a/test-network-k8s/kube/org0/org0-tls-ca.yaml b/test-network-k8s/kube/org0/org0-tls-ca.yaml index a28649df..abc6237b 100644 --- a/test-network-k8s/kube/org0/org0-tls-ca.yaml +++ b/test-network-k8s/kube/org0/org0-tls-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org0-tls-ca" diff --git a/test-network-k8s/kube/org1/org1-admin-cli.yaml b/test-network-k8s/kube/org1/org1-admin-cli.yaml index 5e4f74b9..cfd0c03f 100644 --- a/test-network-k8s/kube/org1/org1-admin-cli.yaml +++ b/test-network-k8s/kube/org1/org1-admin-cli.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} imagePullPolicy: Always env: - name: FABRIC_CFG_PATH diff --git a/test-network-k8s/kube/org1/org1-ecert-ca.yaml b/test-network-k8s/kube/org1/org1-ecert-ca.yaml index a0c4994a..2f552926 100644 --- a/test-network-k8s/kube/org1/org1-ecert-ca.yaml +++ b/test-network-k8s/kube/org1/org1-ecert-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org1-ecert-ca" diff --git a/test-network-k8s/kube/org1/org1-peer1.yaml b/test-network-k8s/kube/org1/org1-peer1.yaml index c913a535..d9a29f8c 100644 --- a/test-network-k8s/kube/org1/org1-peer1.yaml +++ b/test-network-k8s/kube/org1/org1-peer1.yaml @@ -46,7 +46,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} imagePullPolicy: Always envFrom: - configMapRef: @@ -66,7 +66,7 @@ spec: # load the external chaincode builder into the peer image prior to peer launch. initContainers: - name: fabric-ccs-builder - image: ghcr.io/hyperledgendary/fabric-ccs-builder + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ccs-builder imagePullPolicy: Always command: [sh, -c] args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] diff --git a/test-network-k8s/kube/org1/org1-peer2.yaml b/test-network-k8s/kube/org1/org1-peer2.yaml index 8c2f85a7..6d739499 100644 --- a/test-network-k8s/kube/org1/org1-peer2.yaml +++ b/test-network-k8s/kube/org1/org1-peer2.yaml @@ -46,7 +46,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} imagePullPolicy: Always envFrom: - configMapRef: diff --git a/test-network-k8s/kube/org1/org1-tls-ca.yaml b/test-network-k8s/kube/org1/org1-tls-ca.yaml index 71767ff6..d1120498 100644 --- a/test-network-k8s/kube/org1/org1-tls-ca.yaml +++ b/test-network-k8s/kube/org1/org1-tls-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org1-tls-ca" diff --git a/test-network-k8s/kube/org2/org2-admin-cli.yaml b/test-network-k8s/kube/org2/org2-admin-cli.yaml index 6839455a..b39edfaf 100644 --- a/test-network-k8s/kube/org2/org2-admin-cli.yaml +++ b/test-network-k8s/kube/org2/org2-admin-cli.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent env: - name: FABRIC_CFG_PATH diff --git a/test-network-k8s/kube/org2/org2-ecert-ca.yaml b/test-network-k8s/kube/org2/org2-ecert-ca.yaml index f983a5ae..b6c4a50d 100644 --- a/test-network-k8s/kube/org2/org2-ecert-ca.yaml +++ b/test-network-k8s/kube/org2/org2-ecert-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org2-ecert-ca" diff --git a/test-network-k8s/kube/org2/org2-peer1.yaml b/test-network-k8s/kube/org2/org2-peer1.yaml index b77bd70d..609bcaf5 100644 --- a/test-network-k8s/kube/org2/org2-peer1.yaml +++ b/test-network-k8s/kube/org2/org2-peer1.yaml @@ -46,7 +46,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent envFrom: - configMapRef: @@ -66,7 +66,7 @@ spec: # load the external chaincode builder into the peer image prior to peer launch. initContainers: - name: fabric-ccs-builder - image: ghcr.io/hyperledgendary/fabric-ccs-builder + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ccs-builder imagePullPolicy: IfNotPresent command: [sh, -c] args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] diff --git a/test-network-k8s/kube/org2/org2-peer2.yaml b/test-network-k8s/kube/org2/org2-peer2.yaml index e68363c9..871e9ca6 100644 --- a/test-network-k8s/kube/org2/org2-peer2.yaml +++ b/test-network-k8s/kube/org2/org2-peer2.yaml @@ -46,7 +46,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent envFrom: - configMapRef: diff --git a/test-network-k8s/kube/org2/org2-tls-ca.yaml b/test-network-k8s/kube/org2/org2-tls-ca.yaml index c49222e2..e77fe956 100644 --- a/test-network-k8s/kube/org2/org2-tls-ca.yaml +++ b/test-network-k8s/kube/org2/org2-tls-ca.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} env: - name: FABRIC_CA_SERVER_CA_NAME value: "org2-tls-ca" diff --git a/test-network-k8s/network b/test-network-k8s/network index a1008235..ee046cd3 100755 --- a/test-network-k8s/network +++ b/test-network-k8s/network @@ -22,6 +22,7 @@ set -o errexit FABRIC_VERSION=${TEST_NETWORK_FABRIC_VERSION:-2.3.2} FABRIC_CA_VERSION=${TEST_NETWORK_FABRIC_CA_VERSION:-1.5.2} +LOCAL_CONTAINER_REGISTRY=localhost:5000 FABRIC_CONTAINER_REGISTRY=${TEST_NETWORK_FABRIC_CONTAINER_REGISTRY:-hyperledger} NETWORK_NAME=${TEST_NETWORK_NAME:-test-network} CLUSTER_NAME=${TEST_NETWORK_KIND_CLUSTER_NAME:-kind} @@ -34,7 +35,7 @@ LOCAL_REGISTRY_PORT=${TEST_NETWORK_LOCAL_REGISTRY_PORT:-5000} NGINX_HTTP_PORT=${TEST_NETWORK_INGRESS_HTTP_PORT:-80} NGINX_HTTPS_PORT=${TEST_NETWORK_INGRESS_HTTPS_PORT:-443} CHAINCODE_NAME=${TEST_NETWORK_CHAINCODE_NAME:-asset-transfer-basic} -CHAINCODE_IMAGE=${TEST_NETWORK_CHAINCODE_IMAGE:-ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic} +CHAINCODE_IMAGE=${TEST_NETWORK_CHAINCODE_IMAGE:-localhost:5000/fabric-ccaas-asset-transfer-basic} CHAINCODE_LABEL=${TEST_NETWORK_CHAINCODE_LABEL:-basic_1.0} # todo: more complicated config, as these bleed into the yaml descriptors (sed? kustomize? helm (no)? tkn? ansible?...) or other script locations diff --git a/test-network-k8s/scripts/fabric_CAs.sh b/test-network-k8s/scripts/fabric_CAs.sh index a0ee760f..0a167947 100755 --- a/test-network-k8s/scripts/fabric_CAs.sh +++ b/test-network-k8s/scripts/fabric_CAs.sh @@ -8,7 +8,7 @@ function launch_CA() { local yaml=$1 cat ${yaml} \ - | sed 's,{{FABRIC_CONTAINER_REGISTRY}},'${FABRIC_CONTAINER_REGISTRY}',g' \ + | sed 's,{{LOCAL_CONTAINER_REGISTRY}},'${LOCAL_CONTAINER_REGISTRY}',g' \ | sed 's,{{FABRIC_CA_VERSION}},'${FABRIC_CA_VERSION}',g' \ | kubectl -n $NS apply -f - } diff --git a/test-network-k8s/scripts/kind.sh b/test-network-k8s/scripts/kind.sh index 0d4db35d..203d7b9c 100755 --- a/test-network-k8s/scripts/kind.sh +++ b/test-network-k8s/scripts/kind.sh @@ -5,6 +5,38 @@ # SPDX-License-Identifier: Apache-2.0 # +function pull_docker_images() { + push_fn "Pulling docker images for Fabric ${FABRIC_VERSION}" + + docker pull ${FABRIC_CONTAINER_REGISTRY}/fabric-ca:$FABRIC_CA_VERSION + docker pull ${FABRIC_CONTAINER_REGISTRY}/fabric-orderer:$FABRIC_VERSION + docker pull ${FABRIC_CONTAINER_REGISTRY}/fabric-peer:$FABRIC_VERSION + docker pull ${FABRIC_CONTAINER_REGISTRY}/fabric-tools:$FABRIC_VERSION + docker pull ghcr.io/hyperledgendary/fabric-ccs-builder:latest + docker pull ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic:latest + + pop_fn +} + +function push_images_to_local() { + push_fn "Push docker images to local image repository" + + docker tag ${FABRIC_CONTAINER_REGISTRY}/fabric-ca:$FABRIC_CA_VERSION ${LOCAL_CONTAINER_REGISTRY}/fabric-ca:$FABRIC_CA_VERSION + docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-ca:$FABRIC_CA_VERSION + docker tag ${FABRIC_CONTAINER_REGISTRY}/fabric-orderer:$FABRIC_VERSION ${LOCAL_CONTAINER_REGISTRY}/fabric-orderer:$FABRIC_VERSION + docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-orderer:$FABRIC_VERSION + docker tag ${FABRIC_CONTAINER_REGISTRY}/fabric-peer:$FABRIC_VERSION ${LOCAL_CONTAINER_REGISTRY}/fabric-peer:$FABRIC_VERSION + docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-peer:$FABRIC_VERSION + docker tag ${FABRIC_CONTAINER_REGISTRY}/fabric-tools:$FABRIC_VERSION ${LOCAL_CONTAINER_REGISTRY}/fabric-tools:$FABRIC_VERSION + docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-tools:$FABRIC_VERSION + docker tag ghcr.io/hyperledgendary/fabric-ccs-builder:latest ${LOCAL_CONTAINER_REGISTRY}/fabric-ccs-builder:latest + docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-ccs-builder:latest + docker tag ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic:latest ${LOCAL_CONTAINER_REGISTRY}/fabric-ccaas-asset-transfer-basic:latest + docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-ccaas-asset-transfer-basic:latest + + pop_fn +} + function apply_nginx_ingress() { push_fn "Launching Nginx ingress controller" @@ -95,11 +127,6 @@ EOF pop_fn } -function load_kind_image_plane() { - push_fn "Ensuring fabric node images" - pop_fn -} - function kind_delete() { push_fn "Deleting KIND cluster ${CLUSTER_NAME}" @@ -115,6 +142,9 @@ function kind_init() { kind_create apply_nginx_ingress launch_docker_registry + + pull_docker_images + push_images_to_local } function kind_unkind() { diff --git a/test-network-k8s/scripts/test_network.sh b/test-network-k8s/scripts/test_network.sh index 05279609..da0dbb9a 100755 --- a/test-network-k8s/scripts/test_network.sh +++ b/test-network-k8s/scripts/test_network.sh @@ -11,7 +11,7 @@ function launch() { local yaml=$1 cat ${yaml} \ - | sed 's,{{FABRIC_CONTAINER_REGISTRY}},'${FABRIC_CONTAINER_REGISTRY}',g' \ + | sed 's,{{LOCAL_CONTAINER_REGISTRY}},'${LOCAL_CONTAINER_REGISTRY}',g' \ | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' \ | kubectl -n $NS apply -f - } @@ -247,6 +247,9 @@ function stop_services() { function scrub_org_volumes() { push_fn "Scrubbing Fabric volumes" + + # clean job to make this function can be rerun + kubectl -n $NS delete jobs --all # scrub all pv contents kubectl -n $NS create -f kube/job-scrub-fabric-volumes.yaml From 8c1c36ae0978925605ac3bb242fe9dbe91ceabe5 Mon Sep 17 00:00:00 2001 From: Tatsuya Sato Date: Fri, 5 Nov 2021 06:29:22 +0000 Subject: [PATCH 023/106] Fix type error when using the latest sort-keys-recursive The latest version (2.1.2) of sort-keys-recursive adds TypeScript typing, which includes export default function. This change has caused the TS2349 type error. This patch modifies the import form in assetTransfer.ts to fix the error. Signed-off-by: Tatsuya Sato --- asset-transfer-basic/chaincode-javascript/package.json | 2 +- asset-transfer-basic/chaincode-typescript/package.json | 4 ++-- .../chaincode-typescript/src/assetTransfer.ts | 4 ++-- asset-transfer-basic/chaincode-typescript/tsconfig.json | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/asset-transfer-basic/chaincode-javascript/package.json b/asset-transfer-basic/chaincode-javascript/package.json index 6a44f07d..a5e2690f 100644 --- a/asset-transfer-basic/chaincode-javascript/package.json +++ b/asset-transfer-basic/chaincode-javascript/package.json @@ -20,7 +20,7 @@ "fabric-contract-api": "^2.0.0", "fabric-shim": "^2.0.0", "json-stringify-deterministic": "^1.0.1", - "sort-keys-recursive": "^2.0.0" + "sort-keys-recursive": "^2.1.2" }, "devDependencies": { "chai": "^4.1.2", diff --git a/asset-transfer-basic/chaincode-typescript/package.json b/asset-transfer-basic/chaincode-typescript/package.json index befe4a5f..66f41315 100644 --- a/asset-transfer-basic/chaincode-typescript/package.json +++ b/asset-transfer-basic/chaincode-typescript/package.json @@ -23,8 +23,8 @@ "dependencies": { "fabric-contract-api": "^2.0.0", "fabric-shim": "^2.0.0", - "json-stringify-deterministic":"^1.0.0", - "sort-keys-recursive":"^2.0.0" + "json-stringify-deterministic": "^1.0.0", + "sort-keys-recursive": "^2.1.2" }, "devDependencies": { "@types/chai": "^4.1.7", diff --git a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts index 80809475..586c4758 100644 --- a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts +++ b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts @@ -3,8 +3,8 @@ */ // Deterministic JSON.stringify() import {Context, Contract, Info, Returns, Transaction} from 'fabric-contract-api'; -import * as stringify from 'json-stringify-deterministic'; -import * as sortKeysRecursive from 'sort-keys-recursive'; +import stringify from 'json-stringify-deterministic'; +import sortKeysRecursive from 'sort-keys-recursive'; import {Asset} from './asset'; @Info({title: 'AssetTransfer', description: 'Smart contract for trading assets'}) diff --git a/asset-transfer-basic/chaincode-typescript/tsconfig.json b/asset-transfer-basic/chaincode-typescript/tsconfig.json index 80d8e12d..70cc98c9 100644 --- a/asset-transfer-basic/chaincode-typescript/tsconfig.json +++ b/asset-transfer-basic/chaincode-typescript/tsconfig.json @@ -6,6 +6,7 @@ "target": "es2017", "moduleResolution": "node", "module": "commonjs", + "esModuleInterop": true, "declaration": true, "sourceMap": true }, From 8183da6666044a6a69853560aff66edfe0fb1635 Mon Sep 17 00:00:00 2001 From: jkneubuh <86427252+jkneubuh@users.noreply.github.com> Date: Wed, 10 Nov 2021 04:56:57 -0500 Subject: [PATCH 024/106] Add an option to stage docker images locally to KIND (#528) Signed-off-by: Josh Kneubuhl --- test-network-k8s/docs/TEST_NETWORK.md | 2 +- .../kube/org0/org0-admin-cli.yaml | 2 +- test-network-k8s/kube/org0/org0-ecert-ca.yaml | 3 +- test-network-k8s/kube/org0/org0-orderer1.yaml | 4 +-- test-network-k8s/kube/org0/org0-orderer2.yaml | 4 +-- test-network-k8s/kube/org0/org0-orderer3.yaml | 4 +-- test-network-k8s/kube/org0/org0-tls-ca.yaml | 3 +- .../kube/org1/org1-admin-cli.yaml | 4 +-- test-network-k8s/kube/org1/org1-ecert-ca.yaml | 3 +- test-network-k8s/kube/org1/org1-peer1.yaml | 8 ++--- test-network-k8s/kube/org1/org1-peer2.yaml | 4 +-- test-network-k8s/kube/org1/org1-tls-ca.yaml | 3 +- .../kube/org2/org2-admin-cli.yaml | 2 +- test-network-k8s/kube/org2/org2-ecert-ca.yaml | 3 +- test-network-k8s/kube/org2/org2-peer1.yaml | 4 +-- test-network-k8s/kube/org2/org2-peer2.yaml | 2 +- test-network-k8s/kube/org2/org2-tls-ca.yaml | 3 +- test-network-k8s/network | 7 +++- test-network-k8s/scripts/fabric_CAs.sh | 2 +- test-network-k8s/scripts/kind.sh | 32 ++++++++----------- test-network-k8s/scripts/test_network.sh | 2 +- 21 files changed, 54 insertions(+), 47 deletions(-) diff --git a/test-network-k8s/docs/TEST_NETWORK.md b/test-network-k8s/docs/TEST_NETWORK.md index 6f534114..63a9a857 100644 --- a/test-network-k8s/docs/TEST_NETWORK.md +++ b/test-network-k8s/docs/TEST_NETWORK.md @@ -135,7 +135,7 @@ from a public container registry, copying the external builders into the target ```yaml initContainers: - name: fabric-ccs-builder - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ccs-builder + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ccs-builder command: [sh, -c] args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] volumeMounts: diff --git a/test-network-k8s/kube/org0/org0-admin-cli.yaml b/test-network-k8s/kube/org0/org0-admin-cli.yaml index ad32646b..85c81343 100644 --- a/test-network-k8s/kube/org0/org0-admin-cli.yaml +++ b/test-network-k8s/kube/org0/org0-admin-cli.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent env: - name: FABRIC_CFG_PATH diff --git a/test-network-k8s/kube/org0/org0-ecert-ca.yaml b/test-network-k8s/kube/org0/org0-ecert-ca.yaml index 094e9671..4e1960f5 100644 --- a/test-network-k8s/kube/org0/org0-ecert-ca.yaml +++ b/test-network-k8s/kube/org0/org0-ecert-ca.yaml @@ -20,7 +20,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + imagePullPolicy: IfNotPresent env: - name: FABRIC_CA_SERVER_CA_NAME value: "org0-ecert-ca" diff --git a/test-network-k8s/kube/org0/org0-orderer1.yaml b/test-network-k8s/kube/org0/org0-orderer1.yaml index f5c3c702..ce70b59a 100644 --- a/test-network-k8s/kube/org0/org0-orderer1.yaml +++ b/test-network-k8s/kube/org0/org0-orderer1.yaml @@ -43,8 +43,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} - imagePullPolicy: Always + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent envFrom: - configMapRef: name: org0-orderer1-env diff --git a/test-network-k8s/kube/org0/org0-orderer2.yaml b/test-network-k8s/kube/org0/org0-orderer2.yaml index 9a7188f9..0314416d 100644 --- a/test-network-k8s/kube/org0/org0-orderer2.yaml +++ b/test-network-k8s/kube/org0/org0-orderer2.yaml @@ -43,8 +43,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} - imagePullPolicy: Always + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent envFrom: - configMapRef: name: org0-orderer2-env diff --git a/test-network-k8s/kube/org0/org0-orderer3.yaml b/test-network-k8s/kube/org0/org0-orderer3.yaml index b9aa1431..cbca3739 100644 --- a/test-network-k8s/kube/org0/org0-orderer3.yaml +++ b/test-network-k8s/kube/org0/org0-orderer3.yaml @@ -43,8 +43,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} - imagePullPolicy: Always + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-orderer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent envFrom: - configMapRef: name: org0-orderer3-env diff --git a/test-network-k8s/kube/org0/org0-tls-ca.yaml b/test-network-k8s/kube/org0/org0-tls-ca.yaml index abc6237b..0ae21a25 100644 --- a/test-network-k8s/kube/org0/org0-tls-ca.yaml +++ b/test-network-k8s/kube/org0/org0-tls-ca.yaml @@ -20,7 +20,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + imagePullPolicy: IfNotPresent env: - name: FABRIC_CA_SERVER_CA_NAME value: "org0-tls-ca" diff --git a/test-network-k8s/kube/org1/org1-admin-cli.yaml b/test-network-k8s/kube/org1/org1-admin-cli.yaml index cfd0c03f..8086e732 100644 --- a/test-network-k8s/kube/org1/org1-admin-cli.yaml +++ b/test-network-k8s/kube/org1/org1-admin-cli.yaml @@ -20,8 +20,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} - imagePullPolicy: Always + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent env: - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric/config diff --git a/test-network-k8s/kube/org1/org1-ecert-ca.yaml b/test-network-k8s/kube/org1/org1-ecert-ca.yaml index 2f552926..c4a9f4e6 100644 --- a/test-network-k8s/kube/org1/org1-ecert-ca.yaml +++ b/test-network-k8s/kube/org1/org1-ecert-ca.yaml @@ -20,7 +20,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + imagePullPolicy: IfNotPresent env: - name: FABRIC_CA_SERVER_CA_NAME value: "org1-ecert-ca" diff --git a/test-network-k8s/kube/org1/org1-peer1.yaml b/test-network-k8s/kube/org1/org1-peer1.yaml index d9a29f8c..cb879f02 100644 --- a/test-network-k8s/kube/org1/org1-peer1.yaml +++ b/test-network-k8s/kube/org1/org1-peer1.yaml @@ -46,8 +46,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} - imagePullPolicy: Always + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent envFrom: - configMapRef: name: org1-peer1-config @@ -66,8 +66,8 @@ spec: # load the external chaincode builder into the peer image prior to peer launch. initContainers: - name: fabric-ccs-builder - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ccs-builder - imagePullPolicy: Always + image: ghcr.io/hyperledgendary/fabric-ccs-builder + imagePullPolicy: IfNotPresent command: [sh, -c] args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] volumeMounts: diff --git a/test-network-k8s/kube/org1/org1-peer2.yaml b/test-network-k8s/kube/org1/org1-peer2.yaml index 6d739499..a0e99426 100644 --- a/test-network-k8s/kube/org1/org1-peer2.yaml +++ b/test-network-k8s/kube/org1/org1-peer2.yaml @@ -46,8 +46,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} - imagePullPolicy: Always + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + imagePullPolicy: IfNotPresent envFrom: - configMapRef: name: org1-peer2-config diff --git a/test-network-k8s/kube/org1/org1-tls-ca.yaml b/test-network-k8s/kube/org1/org1-tls-ca.yaml index d1120498..a16da691 100644 --- a/test-network-k8s/kube/org1/org1-tls-ca.yaml +++ b/test-network-k8s/kube/org1/org1-tls-ca.yaml @@ -20,7 +20,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + imagePullPolicy: IfNotPresent env: - name: FABRIC_CA_SERVER_CA_NAME value: "org1-tls-ca" diff --git a/test-network-k8s/kube/org2/org2-admin-cli.yaml b/test-network-k8s/kube/org2/org2-admin-cli.yaml index b39edfaf..6839455a 100644 --- a/test-network-k8s/kube/org2/org2-admin-cli.yaml +++ b/test-network-k8s/kube/org2/org2-admin-cli.yaml @@ -20,7 +20,7 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-tools:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent env: - name: FABRIC_CFG_PATH diff --git a/test-network-k8s/kube/org2/org2-ecert-ca.yaml b/test-network-k8s/kube/org2/org2-ecert-ca.yaml index b6c4a50d..216b53be 100644 --- a/test-network-k8s/kube/org2/org2-ecert-ca.yaml +++ b/test-network-k8s/kube/org2/org2-ecert-ca.yaml @@ -20,7 +20,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + imagePullPolicy: IfNotPresent env: - name: FABRIC_CA_SERVER_CA_NAME value: "org2-ecert-ca" diff --git a/test-network-k8s/kube/org2/org2-peer1.yaml b/test-network-k8s/kube/org2/org2-peer1.yaml index 609bcaf5..b77bd70d 100644 --- a/test-network-k8s/kube/org2/org2-peer1.yaml +++ b/test-network-k8s/kube/org2/org2-peer1.yaml @@ -46,7 +46,7 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent envFrom: - configMapRef: @@ -66,7 +66,7 @@ spec: # load the external chaincode builder into the peer image prior to peer launch. initContainers: - name: fabric-ccs-builder - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ccs-builder + image: ghcr.io/hyperledgendary/fabric-ccs-builder imagePullPolicy: IfNotPresent command: [sh, -c] args: ["cp /go/bin/* /var/hyperledger/fabric/chaincode/ccs-builder/bin/"] diff --git a/test-network-k8s/kube/org2/org2-peer2.yaml b/test-network-k8s/kube/org2/org2-peer2.yaml index 871e9ca6..e68363c9 100644 --- a/test-network-k8s/kube/org2/org2-peer2.yaml +++ b/test-network-k8s/kube/org2/org2-peer2.yaml @@ -46,7 +46,7 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-peer:{{FABRIC_VERSION}} imagePullPolicy: IfNotPresent envFrom: - configMapRef: diff --git a/test-network-k8s/kube/org2/org2-tls-ca.yaml b/test-network-k8s/kube/org2/org2-tls-ca.yaml index e77fe956..53ec23db 100644 --- a/test-network-k8s/kube/org2/org2-tls-ca.yaml +++ b/test-network-k8s/kube/org2/org2-tls-ca.yaml @@ -20,7 +20,8 @@ spec: spec: containers: - name: main - image: {{LOCAL_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + image: {{FABRIC_CONTAINER_REGISTRY}}/fabric-ca:{{FABRIC_CA_VERSION}} + imagePullPolicy: IfNotPresent env: - name: FABRIC_CA_SERVER_CA_NAME value: "org2-tls-ca" diff --git a/test-network-k8s/network b/test-network-k8s/network index ee046cd3..f0f34a77 100755 --- a/test-network-k8s/network +++ b/test-network-k8s/network @@ -22,7 +22,6 @@ set -o errexit FABRIC_VERSION=${TEST_NETWORK_FABRIC_VERSION:-2.3.2} FABRIC_CA_VERSION=${TEST_NETWORK_FABRIC_CA_VERSION:-1.5.2} -LOCAL_CONTAINER_REGISTRY=localhost:5000 FABRIC_CONTAINER_REGISTRY=${TEST_NETWORK_FABRIC_CONTAINER_REGISTRY:-hyperledger} NETWORK_NAME=${TEST_NETWORK_NAME:-test-network} CLUSTER_NAME=${TEST_NETWORK_KIND_CLUSTER_NAME:-kind} @@ -32,6 +31,7 @@ LOG_FILE=${TEST_NETWORK_LOG_FILE:-network.log} DEBUG_FILE=${TEST_NETWORK_DEBUG_FILE:-network-debug.log} LOCAL_REGISTRY_NAME=${TEST_NETWORK_LOCAL_REGISTRY_NAME:-kind-registry} LOCAL_REGISTRY_PORT=${TEST_NETWORK_LOCAL_REGISTRY_PORT:-5000} +STAGE_DOCKER_IMAGES=${TEST_NETWORK_STAGE_DOCKER_IMAGES:-false} NGINX_HTTP_PORT=${TEST_NETWORK_INGRESS_HTTP_PORT:-80} NGINX_HTTPS_PORT=${TEST_NETWORK_INGRESS_HTTPS_PORT:-443} CHAINCODE_NAME=${TEST_NETWORK_CHAINCODE_NAME:-asset-transfer-basic} @@ -106,6 +106,11 @@ if [ "${MODE}" == "kind" ]; then kind_init log "🏁 - Cluster is ready." +elif [ "${MODE}" == "load-images" ]; then + log "Loading images to KIND:" + load_docker_images + log "🏁 - Images loaded." + elif [ "${MODE}" == "unkind" ]; then log "Deleting cluster \"${CLUSTER_NAME}\":" kind_unkind diff --git a/test-network-k8s/scripts/fabric_CAs.sh b/test-network-k8s/scripts/fabric_CAs.sh index 0a167947..a0ee760f 100755 --- a/test-network-k8s/scripts/fabric_CAs.sh +++ b/test-network-k8s/scripts/fabric_CAs.sh @@ -8,7 +8,7 @@ function launch_CA() { local yaml=$1 cat ${yaml} \ - | sed 's,{{LOCAL_CONTAINER_REGISTRY}},'${LOCAL_CONTAINER_REGISTRY}',g' \ + | sed 's,{{FABRIC_CONTAINER_REGISTRY}},'${FABRIC_CONTAINER_REGISTRY}',g' \ | sed 's,{{FABRIC_CA_VERSION}},'${FABRIC_CA_VERSION}',g' \ | kubectl -n $NS apply -f - } diff --git a/test-network-k8s/scripts/kind.sh b/test-network-k8s/scripts/kind.sh index 203d7b9c..a6fb1fd6 100755 --- a/test-network-k8s/scripts/kind.sh +++ b/test-network-k8s/scripts/kind.sh @@ -18,23 +18,17 @@ function pull_docker_images() { pop_fn } -function push_images_to_local() { - push_fn "Push docker images to local image repository" +function load_docker_images() { + push_fn "Loading docker images to KIND control plane" - docker tag ${FABRIC_CONTAINER_REGISTRY}/fabric-ca:$FABRIC_CA_VERSION ${LOCAL_CONTAINER_REGISTRY}/fabric-ca:$FABRIC_CA_VERSION - docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-ca:$FABRIC_CA_VERSION - docker tag ${FABRIC_CONTAINER_REGISTRY}/fabric-orderer:$FABRIC_VERSION ${LOCAL_CONTAINER_REGISTRY}/fabric-orderer:$FABRIC_VERSION - docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-orderer:$FABRIC_VERSION - docker tag ${FABRIC_CONTAINER_REGISTRY}/fabric-peer:$FABRIC_VERSION ${LOCAL_CONTAINER_REGISTRY}/fabric-peer:$FABRIC_VERSION - docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-peer:$FABRIC_VERSION - docker tag ${FABRIC_CONTAINER_REGISTRY}/fabric-tools:$FABRIC_VERSION ${LOCAL_CONTAINER_REGISTRY}/fabric-tools:$FABRIC_VERSION - docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-tools:$FABRIC_VERSION - docker tag ghcr.io/hyperledgendary/fabric-ccs-builder:latest ${LOCAL_CONTAINER_REGISTRY}/fabric-ccs-builder:latest - docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-ccs-builder:latest - docker tag ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic:latest ${LOCAL_CONTAINER_REGISTRY}/fabric-ccaas-asset-transfer-basic:latest - docker push ${LOCAL_CONTAINER_REGISTRY}/fabric-ccaas-asset-transfer-basic:latest - - pop_fn + kind load docker-image ${FABRIC_CONTAINER_REGISTRY}/fabric-ca:$FABRIC_CA_VERSION + kind load docker-image ${FABRIC_CONTAINER_REGISTRY}/fabric-orderer:$FABRIC_VERSION + kind load docker-image ${FABRIC_CONTAINER_REGISTRY}/fabric-peer:$FABRIC_VERSION + kind load docker-image ${FABRIC_CONTAINER_REGISTRY}/fabric-tools:$FABRIC_VERSION + kind load docker-image ghcr.io/hyperledgendary/fabric-ccs-builder:latest + kind load docker-image ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic:latest + + pop_fn } function apply_nginx_ingress() { @@ -143,8 +137,10 @@ function kind_init() { apply_nginx_ingress launch_docker_registry - pull_docker_images - push_images_to_local + if [ "${STAGE_DOCKER_IMAGES}" == true ]; then + pull_docker_images + load_docker_images + fi } function kind_unkind() { diff --git a/test-network-k8s/scripts/test_network.sh b/test-network-k8s/scripts/test_network.sh index da0dbb9a..992cd983 100755 --- a/test-network-k8s/scripts/test_network.sh +++ b/test-network-k8s/scripts/test_network.sh @@ -11,7 +11,7 @@ function launch() { local yaml=$1 cat ${yaml} \ - | sed 's,{{LOCAL_CONTAINER_REGISTRY}},'${LOCAL_CONTAINER_REGISTRY}',g' \ + | sed 's,{{FABRIC_CONTAINER_REGISTRY}},'${FABRIC_CONTAINER_REGISTRY}',g' \ | sed 's,{{FABRIC_VERSION}},'${FABRIC_VERSION}',g' \ | kubectl -n $NS apply -f - } From d2eef4786d2b4e9dd9f8a94bfe7d0158fe44c34e Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 10 Nov 2021 17:17:18 +0000 Subject: [PATCH 025/106] Update node version in CI (#534) Several Fabric projects have updated their supported node versions and 16.x is the active LTS version Signed-off-by: James Taylor --- ci/azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 051eccfc..d21a6545 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -11,7 +11,7 @@ variables: FABRIC_VERSION: 2.4 GO_BIN: $(Build.Repository.LocalPath)/bin GO_VER: 1.16.7 - NODE_VER: 12.x + NODE_VER: 16.x PATH: $(Build.Repository.LocalPath)/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin jobs: From 4640ab2e6905e86d94b25f9bd325aabdd1f1857b Mon Sep 17 00:00:00 2001 From: denyeart Date: Wed, 10 Nov 2021 15:15:21 -0500 Subject: [PATCH 026/106] Retire dormant maintainers (#535) Several fabric-samples maintainers have moved on to other projects. See maintainer policies at https://hyperledger-fabric.readthedocs.io/en/latest/CONTRIBUTING.html#becoming-a-maintainer Signed-off-by: David Enyeart --- MAINTAINERS.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 2a4dafb1..a570ea39 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -6,10 +6,7 @@ fabric-samples uses a non-author code review policy, requiring a single approval | Name | GitHub | Chat | email | |---------------------------|------------------|----------------|-------------------------------------| | Arnaud Le Hors | lehors | lehors | lehors@us.ibm.com | -| Bret Harrison | harrisob | bretharrison | harrisob@us.ibm.com | -| Chris Ferris | christo4ferris | cbf | chris.ferris@gmail.com | | Dave Enyeart | denyeart | dave.enyeart | enyeart@us.ibm.com | -| Gari Singh | mastersingh24 | mastersingh24 | gari.r.singh@gmail.com | | Matthew B White | mbwhite | mbwhite | whitemat@uk.ibm.com | | Nikhil Gupta | nikhil550 | negupta | nikhilg550@gmail.com | From 60d5d3e218e4179e69a2c2ac27338fa0d65ee4b7 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 11 Nov 2021 09:35:50 +0000 Subject: [PATCH 027/106] Update application-gateway-typescript (#531) The fabric-gateway node module has been renamed to @hyperledger/fabric-gateway Signed-off-by: James Taylor --- .../application-gateway-typescript/package.json | 2 +- asset-transfer-basic/application-gateway-typescript/src/app.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/asset-transfer-basic/application-gateway-typescript/package.json b/asset-transfer-basic/application-gateway-typescript/package.json index d633b8af..d5b8eaeb 100644 --- a/asset-transfer-basic/application-gateway-typescript/package.json +++ b/asset-transfer-basic/application-gateway-typescript/package.json @@ -20,7 +20,7 @@ "author": "Hyperledger", "license": "Apache-2.0", "dependencies": { - "fabric-gateway": "0.1.0-dev.20211006.12" + "@hyperledger/fabric-gateway": "^0.1.0" }, "devDependencies": { "@tsconfig/node12": "^1.0.9", diff --git a/asset-transfer-basic/application-gateway-typescript/src/app.ts b/asset-transfer-basic/application-gateway-typescript/src/app.ts index 0664ee42..31751e33 100644 --- a/asset-transfer-basic/application-gateway-typescript/src/app.ts +++ b/asset-transfer-basic/application-gateway-typescript/src/app.ts @@ -6,7 +6,7 @@ import * as grpc from '@grpc/grpc-js'; import * as crypto from 'crypto'; -import { connect, Identity, Signer, signers ,Contract} from 'fabric-gateway'; +import { connect, Identity, Signer, signers ,Contract} from '@hyperledger/fabric-gateway'; import { promises as fs } from 'fs'; import * as path from 'path'; From 271dfbb9bcde2d29b8b05190749111f31916bbb5 Mon Sep 17 00:00:00 2001 From: denyeart Date: Mon, 15 Nov 2021 03:36:43 -0500 Subject: [PATCH 028/106] Nominate Josh Kneubuhl as fabric-samples maintainer (#536) Josh has been helping to update samples for the Kubernetes age. He has contributed the test-network-k8s sample and has been active in managing fabric-samples issues. Let's welcome Josh as a fabric-samples maintainer! Signed-off-by: David Enyeart --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index a570ea39..2f4754cb 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -7,6 +7,7 @@ fabric-samples uses a non-author code review policy, requiring a single approval |---------------------------|------------------|----------------|-------------------------------------| | Arnaud Le Hors | lehors | lehors | lehors@us.ibm.com | | Dave Enyeart | denyeart | dave.enyeart | enyeart@us.ibm.com | +| Josh Kneubuhl | jkneubuh | jkneubuhl | jkneubuh@us.ibm.com | | Matthew B White | mbwhite | mbwhite | whitemat@uk.ibm.com | | Nikhil Gupta | nikhil550 | negupta | nikhilg550@gmail.com | From d19a7e4b02a57c36267077a312868594f2692d4a Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Fri, 19 Nov 2021 16:08:26 +0000 Subject: [PATCH 029/106] Setup basic HA features for the Peers (#532) - Add a new label to each peer to mark which org it is in - Create new service per org, that matches this label - so the service can pick from one of multiple pods - Update the kubeproxy to give more choice of ha stratergies - Update the application configmaps and samples to refer to this new service rather than specific peers Signed-off-by: Matthew B White --- test-network-k8s/docs/HIGH_AVAILABILITY.md | 71 +++++++++++++++++++ test-network-k8s/kube/org1/org1-peer1.yaml | 15 +++- test-network-k8s/kube/org1/org1-peer2.yaml | 1 + test-network-k8s/kube/org2/org2-peer1.yaml | 15 +++- test-network-k8s/kube/org2/org2-peer2.yaml | 1 + .../scripts/application_connection.sh | 4 +- test-network-k8s/scripts/chaincode.sh | 17 +++++ test-network-k8s/scripts/kind.sh | 4 ++ test-network-k8s/scripts/test_network.sh | 8 +-- 9 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 test-network-k8s/docs/HIGH_AVAILABILITY.md diff --git a/test-network-k8s/docs/HIGH_AVAILABILITY.md b/test-network-k8s/docs/HIGH_AVAILABILITY.md new file mode 100644 index 00000000..d23a411a --- /dev/null +++ b/test-network-k8s/docs/HIGH_AVAILABILITY.md @@ -0,0 +1,71 @@ +# High Availability + +The peers have been configured so they implemented a essential failover/high-availability configuration. + +Two important notes: + +1. The word 'gateway' in the k8s definitions is being used in a generic way. It is not tied to the concept of the 'Fabric Gateway' component. However using the 'Fabric-Gateway' with the udpated SDKs, make connecting to Fabric even easier. There is a single connection, that can easily be handled with core k8s abilities. Attempting the approach described below with the older SDKs is not recommended. +2. Long Lived gRPC connections. Remember that the connections between components in Fabric are long-lived gRPC connections. From a client application's perspective that means the connection will be load-balanced when initially connected, but unless the connection breaks, it will not be 're-load-balanced'. It's important to keep this in mind. + +## Peer Gateway Services + +Each peer has defined their own K8S service, with the selector specifically choosing only one peer pod. +In this test-network, there are two peers per organization. Using a service with a different selector that +picks both peer pods, allows a degree of load balancing. + +```yaml +--- +apiVersion: v1 +kind: Service +metadata: + name: org2-peer-gateway-svc +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + selector: + org: org2 +``` + +The selector is `org: org2` that is defined in the specification of the Peer's Deployment. + +```yaml + template: + metadata: + labels: + app: org2-peer1 + org: org2 +``` + +## Kube Proxy Configuration +The proxy configuration is set to be `ipvs`. This gives a lot more scope for different load balancing algorthms. +"Round Robin" is the default configuration (as used in this test network). For more information check this [deep dive](https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive) on the Kubernetes blog. + +For this KIND cluster, this is configured by updating the cluster configuration, add the following yaml. + +```yaml +networking: + kubeProxyMode: "ipvs" +``` + +## Application and TLS Configuration + +It is important that applications connect to the `org2-peer-gateway-svc` or `org1-peer-gateway-svc` rather that specific peer services. That way the service can load balance. However if TLS used, errors will occur as the host name that is connected to is different to that used by the application. + +The solution is to add the additional servicename to the hosts field in the SAN section of the TLS certificate. As an example here is the command that is used to create the TLS certificate for org1-peer1. Note the + +```bash +fabric-ca-client enroll --url https://org1-peer1:peerpw@org1-ecert-ca --csr.hosts org1-peer1,org1-peer-gateway-svc --mspdir /var/hyperledger/fabric/organizations/peerOrganizations/org1.example.com/peers/org1-peer1.org1.example.com/msp +``` + +## Summary + +The FabricGateway and updated SDKs, improve the connection from a client application to Fabric, by needing only a single connection to one peer. By using a K8S service fronting two or more peer pods, a degree of load-balancing can be achieved. Remember that this will only be load balanced when the connection is first created. If a single peer becomes heavily loaded, K8S will not move any existing connection. + +To achieve this you would need to have a monitoring system that can trigger applications to disconnect and reconnect. + +If the connection drops, the application can reconnect and will get to a working peer. + + + diff --git a/test-network-k8s/kube/org1/org1-peer1.yaml b/test-network-k8s/kube/org1/org1-peer1.yaml index cb879f02..f1f40ac4 100644 --- a/test-network-k8s/kube/org1/org1-peer1.yaml +++ b/test-network-k8s/kube/org1/org1-peer1.yaml @@ -43,6 +43,7 @@ spec: metadata: labels: app: org1-peer1 + org: org1 spec: containers: - name: main @@ -100,4 +101,16 @@ spec: port: 9443 protocol: TCP selector: - app: org1-peer1 \ No newline at end of file + app: org1-peer1 +--- +apiVersion: v1 +kind: Service +metadata: + name: org1-peer-gateway-svc +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + selector: + org: org1 \ No newline at end of file diff --git a/test-network-k8s/kube/org1/org1-peer2.yaml b/test-network-k8s/kube/org1/org1-peer2.yaml index a0e99426..78f57862 100644 --- a/test-network-k8s/kube/org1/org1-peer2.yaml +++ b/test-network-k8s/kube/org1/org1-peer2.yaml @@ -43,6 +43,7 @@ spec: metadata: labels: app: org1-peer2 + org: org1 spec: containers: - name: main diff --git a/test-network-k8s/kube/org2/org2-peer1.yaml b/test-network-k8s/kube/org2/org2-peer1.yaml index b77bd70d..7dba924d 100644 --- a/test-network-k8s/kube/org2/org2-peer1.yaml +++ b/test-network-k8s/kube/org2/org2-peer1.yaml @@ -43,6 +43,7 @@ spec: metadata: labels: app: org2-peer1 + org: org2 spec: containers: - name: main @@ -101,4 +102,16 @@ spec: port: 9443 protocol: TCP selector: - app: org2-peer1 \ No newline at end of file + app: org2-peer1 +--- +apiVersion: v1 +kind: Service +metadata: + name: org2-peer-gateway-svc +spec: + ports: + - name: gossip + port: 7051 + protocol: TCP + selector: + org: org2 diff --git a/test-network-k8s/kube/org2/org2-peer2.yaml b/test-network-k8s/kube/org2/org2-peer2.yaml index e68363c9..3b80025f 100644 --- a/test-network-k8s/kube/org2/org2-peer2.yaml +++ b/test-network-k8s/kube/org2/org2-peer2.yaml @@ -43,6 +43,7 @@ spec: metadata: labels: app: org2-peer2 + org: org2 spec: containers: - name: main diff --git a/test-network-k8s/scripts/application_connection.sh b/test-network-k8s/scripts/application_connection.sh index 9563b128..25d451a6 100755 --- a/test-network-k8s/scripts/application_connection.sh +++ b/test-network-k8s/scripts/application_connection.sh @@ -100,8 +100,8 @@ data: fabric_channel: ${CHANNEL_NAME} fabric_contract: ${CHAINCODE_NAME} fabric_wallet_dir: /fabric/application/wallet - fabric_gateway_hostport: org1-peer1:7051 - fabric_gateway_sslHostOverride: org1-peer1 + fabric_gateway_hostport: org1-peer-gateway-svc:7051 + fabric_gateway_sslHostOverride: org1-peer-gateway-svc fabric_user: appuser_org1 fabric_gateway_tlsCertPath: /fabric/tlscacerts/org1-tls-ca.pem EOF diff --git a/test-network-k8s/scripts/chaincode.sh b/test-network-k8s/scripts/chaincode.sh index c0fec221..cb066188 100755 --- a/test-network-k8s/scripts/chaincode.sh +++ b/test-network-k8s/scripts/chaincode.sh @@ -111,10 +111,27 @@ function query_chaincode_metadata() { set -x local args='{"Args":["org.hyperledger.fabric:GetMetadata"]}' # todo: mangle additional $@ parameters with bash escape quotations + log 'Org1-Peer1:' echo ' export CORE_PEER_ADDRESS=org1-peer1:7051 peer chaincode query -n '${CHAINCODE_NAME}' -C '${CHANNEL_NAME}' -c '"'$args'"' ' | exec kubectl -n $NS exec deploy/org1-admin-cli -c main -i -- /bin/bash + + log '' + log 'Org1-Peer2:' + echo ' + export CORE_PEER_ADDRESS=org1-peer2:7051 + peer chaincode query -n '${CHAINCODE_NAME}' -C '${CHANNEL_NAME}' -c '"'$args'"' + ' | exec kubectl -n $NS exec deploy/org1-admin-cli -c main -i -- /bin/bash + + log '' + log 'Org1-Peer-SVC:' + echo ' + export CORE_PEER_ADDRESS=org1-peer-svc:7051 + peer chaincode query -n '${CHAINCODE_NAME}' -C '${CHANNEL_NAME}' -c '"'$args'"' + ' | exec kubectl -n $NS exec deploy/org1-admin-cli -c main -i -- /bin/bash + + } function invoke_chaincode() { diff --git a/test-network-k8s/scripts/kind.sh b/test-network-k8s/scripts/kind.sh index a6fb1fd6..67a3dd6a 100755 --- a/test-network-k8s/scripts/kind.sh +++ b/test-network-k8s/scripts/kind.sh @@ -54,6 +54,8 @@ function kind_create() { local ingress_http_port=${NGINX_HTTP_PORT} local ingress_https_port=${NGINX_HTTPS_PORT} + # the 'ipvs'proxy mode permits better HA abilities + cat < Date: Fri, 19 Nov 2021 11:09:58 -0500 Subject: [PATCH 030/106] Address Issue #511 with docs and better error handling (#533) * Address Issue #511 with docs and better error handling Signed-off-by: Josh Kneubuhl * Set the TEST_NETWORK_FABRIC_VERSION in documentation for local development. Signed-off-by: Josh Kneubuhl --- test-network-k8s/docs/KUBERNETES.md | 39 ++++++++++++++++++++++++++- test-network-k8s/network | 4 ++- test-network-k8s/scripts/chaincode.sh | 3 ++- test-network-k8s/scripts/utils.sh | 10 +++++-- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/test-network-k8s/docs/KUBERNETES.md b/test-network-k8s/docs/KUBERNETES.md index 6472e1cf..6570cebd 100644 --- a/test-network-k8s/docs/KUBERNETES.md +++ b/test-network-k8s/docs/KUBERNETES.md @@ -131,8 +131,45 @@ to Pods deployed to the local cluster. For dev/test/CI based flows using an external registry, the traditional Kubernetes practice of [Adding ImagePullSecrets to a service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account) -still applies. +still applies. +In some environments, KIND may encounter issues loading the Fabric docker images from the public container +registries. In addition, for Fabric development it can be advantageous to work with Docker images built +locally, bypassing the public images entirely. For these scenarios, images may also be [directly loaded](https://kind.sigs.k8s.io/docs/user/quick-start/#loading-an-image-into-your-cluster) +into the KIND image plane, bypassing the container registry. + +The `./network` script supports these additional modes via: + +1. For network-constrained environments, pull all images to the local docker cache and load to KIND: +```shell +export TEST_NETWORK_STAGE_DOCKER_IMAGES=true + +./network kind +./network up +``` + +2. For alternate registries (e.g. local or Fabric CI/CD builds): +```shell +./network kind + +export TEST_NETWORK_FABRIC_CONTAINER_REGISTRY=hyperledger-fabric.jfrog.io +export TEST_NETWORK_FABRIC_VERSION=amd64-latest +export TEST_NETWORK_FABRIC_CA_VERSION=amd64-latest + +./network up +``` + +3. For working with Fabric images built locally: +```shell +./network kind + +make docker # in hyperledger/fabric + +export TEST_NETWORK_FABRIC_VERSION=2.4.0 + +./network load-images +./network up +``` ## Cloud Vendors diff --git a/test-network-k8s/network b/test-network-k8s/network index f0f34a77..7836f1fe 100755 --- a/test-network-k8s/network +++ b/test-network-k8s/network @@ -35,7 +35,7 @@ STAGE_DOCKER_IMAGES=${TEST_NETWORK_STAGE_DOCKER_IMAGES:-false} NGINX_HTTP_PORT=${TEST_NETWORK_INGRESS_HTTP_PORT:-80} NGINX_HTTPS_PORT=${TEST_NETWORK_INGRESS_HTTPS_PORT:-443} CHAINCODE_NAME=${TEST_NETWORK_CHAINCODE_NAME:-asset-transfer-basic} -CHAINCODE_IMAGE=${TEST_NETWORK_CHAINCODE_IMAGE:-localhost:5000/fabric-ccaas-asset-transfer-basic} +CHAINCODE_IMAGE=${TEST_NETWORK_CHAINCODE_IMAGE:-ghcr.io/hyperledgendary/fabric-ccaas-asset-transfer-basic:latest} CHAINCODE_LABEL=${TEST_NETWORK_CHAINCODE_LABEL:-basic_1.0} # todo: more complicated config, as these bleed into the yaml descriptors (sed? kustomize? helm (no)? tkn? ansible?...) or other script locations @@ -59,6 +59,7 @@ function print_help() { log "--- Cluster Information" log "Cluster name \t\t: ${CLUSTER_NAME}" log "Cluster namespace \t: ${NS}" + log "Fabric Registry \t: ${FABRIC_CONTAINER_REGISTRY}" log "Local Registry \t\t: ${LOCAL_REGISTRY_NAME}" log "Local Registry port \t: ${LOCAL_REGISTRY_PORT}" log "nginx http port \t: ${NGINX_HTTP_PORT}" @@ -70,6 +71,7 @@ function print_help() { log + echo todo: help output, parse mode, flags, env, etc. } diff --git a/test-network-k8s/scripts/chaincode.sh b/test-network-k8s/scripts/chaincode.sh index cb066188..a4f8f691 100755 --- a/test-network-k8s/scripts/chaincode.sh +++ b/test-network-k8s/scripts/chaincode.sh @@ -154,7 +154,8 @@ function invoke_chaincode() { # Normally the chaincode ID is emitted by the peer install command. In this case, we'll generate the # package ID as the sha-256 checksum of the chaincode archive. function set_chaincode_id() { - local cc_sha256=$(shasum -a 256 build/chaincode/${CHAINCODE_NAME}.tgz | tr -s ' ' | cut -d ' ' -f 1) + local cc_package=build/chaincode/${CHAINCODE_NAME}.tgz + cc_sha256=$(shasum -a 256 ${cc_package} | tr -s ' ' | cut -d ' ' -f 1) CHAINCODE_ID=${CHAINCODE_LABEL}:${cc_sha256} } diff --git a/test-network-k8s/scripts/utils.sh b/test-network-k8s/scripts/utils.sh index b777865c..14f4697b 100644 --- a/test-network-k8s/scripts/utils.sh +++ b/test-network-k8s/scripts/utils.sh @@ -47,11 +47,14 @@ function log() { function pop_fn() { # echo exiting ${FUNCNAME[1]} - local res=$1 if [ $# -eq 0 ]; then echo -ne "\r✅" >> ${LOG_FILE} + echo "" >> ${LOG_FILE} + return + fi - elif [ $res -eq 0 ]; then + local res=$1 + if [ $res -eq 0 ]; then echo -ne "\r✅" >> ${LOG_FILE} elif [ $res -eq 1 ]; then @@ -60,6 +63,9 @@ function pop_fn() { elif [ $res -eq 2 ]; then echo -ne "\r☠️" >> ${LOG_FILE} + elif [ $res -eq 127 ]; then + echo -ne "\r☠️" >> ${LOG_FILE} + else echo -ne "\r" >> ${LOG_FILE} fi From 22c54b4690c738ef96ff2c6e04fcae3812cad52b Mon Sep 17 00:00:00 2001 From: Dave Enyeart Date: Mon, 22 Nov 2021 03:54:14 -0500 Subject: [PATCH 031/106] Fix test network nano peer4 id (#541) Fix CORE_PEER_ID for peer4. This fix ensures that peer3 and peer4 don't share the same chaincode container. Signed-off-by: David Enyeart --- test-network-nano-bash/peer4.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-network-nano-bash/peer4.sh b/test-network-nano-bash/peer4.sh index a62afe58..22e95ace 100755 --- a/test-network-nano-bash/peer4.sh +++ b/test-network-nano-bash/peer4.sh @@ -16,7 +16,7 @@ export CORE_PEER_TLS_ENABLED=true export CORE_PEER_TLS_CERT_FILE="${PWD}"/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.crt export CORE_PEER_TLS_KEY_FILE="${PWD}"/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.key export CORE_PEER_TLS_ROOTCERT_FILE="${PWD}"/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt -export CORE_PEER_ID=peer0.org2.example.com +export CORE_PEER_ID=peer1.org2.example.com export CORE_PEER_ADDRESS=127.0.0.1:7057 export CORE_PEER_LISTENADDRESS=127.0.0.1:7057 export CORE_PEER_CHAINCODEADDRESS="${CCADDR}":7058 From f898a3768db350ef2e5df33f9e08f9c53414a78d Mon Sep 17 00:00:00 2001 From: Dave Enyeart Date: Mon, 22 Nov 2021 03:54:39 -0500 Subject: [PATCH 032/106] Update test-network-k8s readme with High Availability doc link (#540) Signed-off-by: David Enyeart --- test-network-k8s/docs/README.md | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/test-network-k8s/docs/README.md b/test-network-k8s/docs/README.md index 9319e8f8..cd21bdc9 100644 --- a/test-network-k8s/docs/README.md +++ b/test-network-k8s/docs/README.md @@ -1,32 +1,32 @@ -# Kubernetes Test Network +# Kubernetes Test Network -Starting in release 2.0, Hyperledger introduced the [test-network](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html) -to serve as both an accelerator and learning resource for running Fabric networks. In addition to -providing a study guide for operational patterns, the test-network provided a baseline environment for members of -the Fabric community to quickly get up to speed with a working, local system, author smart contracts, and develop +Starting in release 2.0, Hyperledger introduced the [test-network](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html) +to serve as both an accelerator and learning resource for running Fabric networks. In addition to +providing a study guide for operational patterns, the test-network provided a baseline environment for members of +the Fabric community to quickly get up to speed with a working, local system, author smart contracts, and develop simple blockchain applications. While test-network provided a solid foundation for casual Fabric development, the over-reliance on -[Docker Compose](https://docs.docker.com/compose/) introduced tremendous, non-trivial complexity when transitioning -applications to production. Without belaboring the many issues and anti-patterns present in the Compose-based -test network, we'll submit that the best path forward is to _align_ the development and production patterns around a +[Docker Compose](https://docs.docker.com/compose/) introduced tremendous, non-trivial complexity when transitioning +applications to production. Without belaboring the many issues and anti-patterns present in the Compose-based +test network, we'll submit that the best path forward is to _align_ the development and production patterns around a common orchestration framework - Kubernetes. -Similar to Fabric, Kubernetes introduces a steep learning curve and presents a dizzying array of operational -flexibility. In this guide, we'll outline the design considerations in the [`./network`](../network) -scripts, provide a supplement to the [Fabric CA Deployment Guide](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/ca-deploy.html), +Similar to Fabric, Kubernetes introduces a steep learning curve and presents a dizzying array of operational +flexibility. In this guide, we'll outline the design considerations in the [`./network`](../network) +scripts, provide a supplement to the [Fabric CA Deployment Guide](https://hyperledger-fabric-ca.readthedocs.io/en/latest/deployguide/ca-deploy.html), and build up to a reference model for realistic production deployments on Kubernetes. -_Ahoy!_ +_Ahoy!_ ## Network Topology The Kube test network establishes as consortium among a dedicated ordering organization and two peer organizations. -Participation in the network is managed over a channel, and transactions are committed to the blockchain ledgers by -invoking the [asset-transfer-basic](https://github.com/hyperledgendary/fabric-ccaas-asset-transfer-basic) -_Chaincode-as-a-Service_ running in a shared Kubernetes namespace. Each organization maintains indepedendent TLS -and ECert CAs for management of local, channel, and user MSP contexts. +Participation in the network is managed over a channel, and transactions are committed to the blockchain ledgers by +invoking the [asset-transfer-basic](https://github.com/hyperledgendary/fabric-ccaas-asset-transfer-basic) +_Chaincode-as-a-Service_ running in a shared Kubernetes namespace. Each organization maintains indepedendent TLS +and ECert CAs for management of local, channel, and user MSP contexts. ![Test Network](images/test-network.png) @@ -34,16 +34,16 @@ and ECert CAs for management of local, channel, and user MSP contexts. ## Detailed Guides - [`./network`](NETWORK.md) -- [Working with Kubernetes](KUBERNETES.md) +- [Working with Kubernetes](KUBERNETES.md) - [Certificate Authorities](CA.md) - [Planning for a CA](CA.md#planning-for-a-ca) - [Deploy the TLS CAs](CA.md#deploy-the-tls-cas) - [Deploy the ECert CAs](CA.md#deploy-the-organization-ca) -- [Launching the Test Network](TEST_NETWORK.md) +- [Launching the Test Network](TEST_NETWORK.md) - [Registering and Enrolling Identities](CA.md#registering-and-enrolling-identities) - [Assembling Node MSPs](link) - [Deploy Orderers and Peers](link) -- [Working with Channels](CHANNELS.md) -- [Working with Chaincode](CHAINCODE.md) -- [Working with Applications](APPLICATIONS.md) - +- [Working with Channels](CHANNELS.md) +- [Working with Chaincode](CHAINCODE.md) +- [Working with Applications](APPLICATIONS.md) +- [High Availability](HIGH_AVAILABILITY.md) From 3d17cf066dd86ec6649ffd81a8b2ca8670dfdcfb Mon Sep 17 00:00:00 2001 From: sapthasurendran <48531319+sapthasurendran@users.noreply.github.com> Date: Mon, 22 Nov 2021 14:25:14 +0530 Subject: [PATCH 033/106] Updated fabric-gateway changes and added node14 dependency (#539) Signed-off-by: sapthasurendran --- .../application-gateway-typescript/package.json | 6 +++--- .../application-gateway-typescript/tsconfig.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/asset-transfer-basic/application-gateway-typescript/package.json b/asset-transfer-basic/application-gateway-typescript/package.json index d5b8eaeb..014caa7f 100644 --- a/asset-transfer-basic/application-gateway-typescript/package.json +++ b/asset-transfer-basic/application-gateway-typescript/package.json @@ -5,7 +5,7 @@ "main": "dist/index.js", "typings": "dist/index.d.ts", "engines": { - "node": ">=12", + "node": ">=14", "npm": ">=5" }, "scripts": { @@ -20,10 +20,10 @@ "author": "Hyperledger", "license": "Apache-2.0", "dependencies": { - "@hyperledger/fabric-gateway": "^0.1.0" + "@hyperledger/fabric-gateway": "unstable" }, "devDependencies": { - "@tsconfig/node12": "^1.0.9", + "@tsconfig/node14": "^1.0.1", "@typescript-eslint/eslint-plugin": "^4.31.2", "@typescript-eslint/parser": "^4.31.2", "eslint": "^7.32.0", diff --git a/asset-transfer-basic/application-gateway-typescript/tsconfig.json b/asset-transfer-basic/application-gateway-typescript/tsconfig.json index efc75170..2052fb6e 100644 --- a/asset-transfer-basic/application-gateway-typescript/tsconfig.json +++ b/asset-transfer-basic/application-gateway-typescript/tsconfig.json @@ -1,5 +1,5 @@ { - "extends":"@tsconfig/node12/tsconfig.json", + "extends":"@tsconfig/node14/tsconfig.json", "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true, From a97e8d1267fafb013aadae6850312c1b07a1ecd8 Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Mon, 22 Nov 2021 13:25:38 +0000 Subject: [PATCH 034/106] Get label for chaincode from metadata.json (#509) Signed-off-by: Matthew B White --- test-network-k8s/scripts/chaincode.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test-network-k8s/scripts/chaincode.sh b/test-network-k8s/scripts/chaincode.sh index a4f8f691..f2c8f24b 100755 --- a/test-network-k8s/scripts/chaincode.sh +++ b/test-network-k8s/scripts/chaincode.sh @@ -157,7 +157,9 @@ function set_chaincode_id() { local cc_package=build/chaincode/${CHAINCODE_NAME}.tgz cc_sha256=$(shasum -a 256 ${cc_package} | tr -s ' ' | cut -d ' ' -f 1) - CHAINCODE_ID=${CHAINCODE_LABEL}:${cc_sha256} + label=$( jq -r '.label' chaincode/${CHAINCODE_NAME}/metadata.json) + + CHAINCODE_ID=${label}:${cc_sha256} } # Package and install the chaincode, but do not activate. From ce666380352d00711e526034804d1b13243386d6 Mon Sep 17 00:00:00 2001 From: fraVlaca <86831094+fraVlaca@users.noreply.github.com> Date: Wed, 24 Nov 2021 16:04:42 +0000 Subject: [PATCH 035/106] Extend test network to support prometheus/grafana performances framework (#542) Signed-off-by: fraVlaca --- test-network/docker/docker-compose-test-net.yaml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test-network/docker/docker-compose-test-net.yaml b/test-network/docker/docker-compose-test-net.yaml index c070f82e..87f68318 100644 --- a/test-network/docker/docker-compose-test-net.yaml +++ b/test-network/docker/docker-compose-test-net.yaml @@ -43,7 +43,8 @@ services: - ORDERER_ADMIN_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] - ORDERER_ADMIN_TLS_CLIENTROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] - ORDERER_ADMIN_LISTENADDRESS=0.0.0.0:7053 - - ORDERER_OPERATIONS_LISTENADDRESS=0.0.0.0:17050 + - ORDERER_OPERATIONS_LISTENADDRESS=orderer.example.com:9443 + - ORDERER_METRICS_PROVIDER=prometheus working_dir: /opt/gopath/src/github.com/hyperledger/fabric command: orderer volumes: @@ -54,7 +55,7 @@ services: ports: - 7050:7050 - 7053:7053 - - 17050:17050 + - 9443:9443 networks: - test @@ -83,7 +84,8 @@ services: - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 - CORE_PEER_LOCALMSPID=Org1MSP - - CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:17051 + - CORE_OPERATIONS_LISTENADDRESS=peer0.org1.example.com:9444 + - CORE_METRICS_PROVIDER=prometheus volumes: - ${DOCKER_SOCK}:/host/var/run/docker.sock - ../organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp @@ -93,7 +95,7 @@ services: command: peer node start ports: - 7051:7051 - - 17051:17051 + - 9444:9444 networks: - test @@ -122,7 +124,8 @@ services: - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:9051 - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:9051 - CORE_PEER_LOCALMSPID=Org2MSP - - CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:19051 + - CORE_OPERATIONS_LISTENADDRESS=peer0.org2.example.com:9445 + - CORE_METRICS_PROVIDER=prometheus volumes: - ${DOCKER_SOCK}:/host/var/run/docker.sock - ../organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp @@ -132,7 +135,7 @@ services: command: peer node start ports: - 9051:9051 - - 19051:19051 + - 9445:9445 networks: - test From 7fd6edb662897b4ae7bef8c1dded0a9459070f4c Mon Sep 17 00:00:00 2001 From: David Faulstich Diniz Reis Date: Thu, 25 Nov 2021 12:51:51 -0300 Subject: [PATCH 036/106] Query assets with pagination functions of marbles02 and asset_transfer_ledger_chaincode chaincodes without ResponseMetadata fetchedRecordsCount and bookmark (#547) Signed-off-by: David Faulstich Diniz Reis --- .../application-javascript/app.js | 9 ++++++++- .../application-javascript/package.json | 1 + .../lib/asset_transfer_ledger_chaincode.js | 17 +++++++++++------ .../marbles02/javascript/marbles_chaincode.js | 16 ++++++++++++---- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/asset-transfer-ledger-queries/application-javascript/app.js b/asset-transfer-ledger-queries/application-javascript/app.js index bc33a89c..73fc83a1 100644 --- a/asset-transfer-ledger-queries/application-javascript/app.js +++ b/asset-transfer-ledger-queries/application-javascript/app.js @@ -191,7 +191,14 @@ async function main() { // Rich Query with Pagination (Only supported if CouchDB is used as state database) console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Tom" assets'); - result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Tom"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '3', ''); + result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Tom"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', ''); + console.log(`*** Result: ${prettyJSONString(result.toString())}`); + + // Recover the bookmark from previous query. Normally it will be inside a variable. + const resultJson = JSON.parse(result.toString()); + + console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Tom" assets next page'); + result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Tom"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', resultJson.ResponseMetadata.Bookmark); console.log(`*** Result: ${prettyJSONString(result.toString())}`); console.log('\n--> Submit Transaction: TransferAssetByColor, transfer all yellow assets to new owner(Michel)'); diff --git a/asset-transfer-ledger-queries/application-javascript/package.json b/asset-transfer-ledger-queries/application-javascript/package.json index 8d92146a..a8a35073 100644 --- a/asset-transfer-ledger-queries/application-javascript/package.json +++ b/asset-transfer-ledger-queries/application-javascript/package.json @@ -10,6 +10,7 @@ "author": "Hyperledger", "license": "Apache-2.0", "scripts": { + "run": "node app.js", "lint": "eslint *.js" }, "dependencies": { diff --git a/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js b/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js index da83bb58..1fe1d29d 100644 --- a/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js +++ b/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js @@ -62,10 +62,10 @@ // curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"size\":\"desc\"},{\"docType\":\"desc\"},{\"owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1_assets/_index // Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database): -// peer chaincode query -C CHANNEL_NAME -n asset_transfer -c '{"Args":["QueryAssets","{\"selector\":{\"docType\":\"asset\",\"owner\":\"Tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}' +// peer chaincode query -C CHANNEL_NAME -n ledger -c '{"Args":["QueryAssets","{\"selector\":{\"docType\":\"asset\",\"owner\":\"Tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}' // Rich Query with index design doc specified only (Only supported if CouchDB is used as state database): -// peer chaincode query -C CHANNEL_NAME -n asset_transfer -c '{"Args":["QueryAssets","{\"selector\":{\"docType\":{\"$eq\":\"asset\"},\"owner\":{\"$eq\":\"Tom\"},\"size\":{\"$gt\":0}},\"fields\":[\"docType\",\"owner\",\"size\"],\"sort\":[{\"size\":\"desc\"}],\"use_index\":\"_design/indexSizeSortDoc\"}"]}' +// peer chaincode query -C CHANNEL_NAME -n ledger -c '{"Args":["QueryAssets","{\"selector\":{\"docType\":{\"$eq\":\"asset\"},\"owner\":{\"$eq\":\"Tom\"},\"size\":{\"$gt\":0}},\"fields\":[\"docType\",\"owner\",\"size\"],\"sort\":[{\"size\":\"desc\"}],\"use_index\":\"_design/indexSizeSortDoc\"}"]}' 'use strict'; @@ -262,12 +262,15 @@ class Chaincode extends Contract { async GetAssetsByRangeWithPagination(ctx, startKey, endKey, pageSize, bookmark) { const {iterator, metadata} = await ctx.stub.getStateByRangeWithPagination(startKey, endKey, pageSize, bookmark); - const results = await this._GetAllResults(iterator, false); + let results = {}; + + results.results = await this._GetAllResults(iterator, false); results.ResponseMetadata = { - RecordsCount: metadata.fetched_records_count, + RecordsCount: metadata.fetchedRecordsCount, Bookmark: metadata.bookmark, }; + return JSON.stringify(results); } @@ -282,10 +285,12 @@ class Chaincode extends Contract { async QueryAssetsWithPagination(ctx, queryString, pageSize, bookmark) { const {iterator, metadata} = await ctx.stub.getQueryResultWithPagination(queryString, pageSize, bookmark); - const results = await this._GetAllResults(iterator, false); + let results = {}; + + results.results = await this._GetAllResults(iterator, false); results.ResponseMetadata = { - RecordsCount: metadata.fetched_records_count, + RecordsCount: metadata.fetchedRecordsCount, Bookmark: metadata.bookmark, }; diff --git a/chaincode/marbles02/javascript/marbles_chaincode.js b/chaincode/marbles02/javascript/marbles_chaincode.js index 7536178c..a4b3547f 100644 --- a/chaincode/marbles02/javascript/marbles_chaincode.js +++ b/chaincode/marbles02/javascript/marbles_chaincode.js @@ -440,12 +440,17 @@ let Chaincode = class { const { iterator, metadata } = await stub.getStateByRangeWithPagination(startKey, endKey, pageSize, bookmark); const getAllResults = thisClass['getAllResults']; - const results = await getAllResults(iterator, false); + + let results = {}; + + results.results = await getAllResults(iterator, false); + // use RecordsCount and Bookmark to keep consistency with the go sample results.ResponseMetadata = { - RecordsCount: metadata.fetched_records_count, + RecordsCount: metadata.fetchedRecordsCount, Bookmark: metadata.bookmark, }; + return Buffer.from(JSON.stringify(results)); } @@ -467,10 +472,13 @@ let Chaincode = class { const { iterator, metadata } = await stub.getQueryResultWithPagination(queryString, pageSize, bookmark); const getAllResults = thisClass['getAllResults']; - const results = await getAllResults(iterator, false); + let results = {}; + + results.results = await getAllResults(iterator, false); + // use RecordsCount and Bookmark to keep consistency with the go sample results.ResponseMetadata = { - RecordsCount: metadata.fetched_records_count, + RecordsCount: metadata.fetchedRecordsCount, Bookmark: metadata.bookmark, }; From e963ddc726f7e869dce39132351d5592b2219307 Mon Sep 17 00:00:00 2001 From: sapthasurendran <48531319+sapthasurendran@users.noreply.github.com> Date: Thu, 9 Dec 2021 15:14:25 +0530 Subject: [PATCH 037/106] lint Fix (#555) Signed-off-by: sapthasurendran --- asset-transfer-abac/chaincode-go/go.mod | 2 +- asset-transfer-abac/chaincode-go/go.sum | 11 ++++++++ asset-transfer-basic/application-go/go.mod | 2 +- asset-transfer-basic/application-go/go.sum | 11 ++++++++ asset-transfer-basic/chaincode-go/go.mod | 2 +- asset-transfer-basic/chaincode-go/go.sum | 11 ++++++++ .../chaincode-go/go.mod | 2 +- .../chaincode-go/go.sum | 11 ++++++++ .../chaincode-go/go.mod | 2 +- .../chaincode-go/go.sum | 11 ++++++++ .../chaincode-go/go.mod | 2 +- .../chaincode-go/go.sum | 11 ++++++++ .../application-javascript/package.json | 1 - auction-dutch/chaincode-go/go.mod | 2 +- auction-dutch/chaincode-go/go.sum | 11 ++++++++ auction-simple/chaincode-go/go.mod | 2 +- auction-simple/chaincode-go/go.sum | 11 ++++++++ .../organization/digibank/contract-go/go.mod | 2 +- .../organization/digibank/contract-go/go.sum | 27 +++++++++---------- .../magnetocorp/contract-go/go.mod | 2 +- .../magnetocorp/contract-go/go.sum | 11 ++++++++ high-throughput/application-go/go.mod | 2 +- high-throughput/application-go/go.sum | 11 ++++++++ high-throughput/chaincode-go/go.mod | 2 +- high-throughput/chaincode-go/go.sum | 11 ++++++++ token-erc-1155/chaincode-go/go.mod | 2 +- token-erc-1155/chaincode-go/go.sum | 11 ++++++++ token-erc-20/chaincode-go/go.mod | 2 +- token-erc-20/chaincode-go/go.sum | 11 ++++++++ token-utxo/chaincode-go/go.mod | 2 +- token-utxo/chaincode-go/go.sum | 11 ++++++++ 31 files changed, 181 insertions(+), 31 deletions(-) diff --git a/asset-transfer-abac/chaincode-go/go.mod b/asset-transfer-abac/chaincode-go/go.mod index 4827829f..84a55d36 100644 --- a/asset-transfer-abac/chaincode-go/go.mod +++ b/asset-transfer-abac/chaincode-go/go.mod @@ -4,5 +4,5 @@ go 1.15 require ( github.com/hyperledger/fabric-contract-api-go v1.1.1 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/asset-transfer-abac/chaincode-go/go.sum b/asset-transfer-abac/chaincode-go/go.sum index 81e30b4a..6544df42 100644 --- a/asset-transfer-abac/chaincode-go/go.sum +++ b/asset-transfer-abac/chaincode-go/go.sum @@ -101,6 +101,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -109,6 +110,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -119,6 +122,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -136,6 +141,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -143,6 +150,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -153,6 +162,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-basic/application-go/go.mod b/asset-transfer-basic/application-go/go.mod index 0db68899..85e1bc42 100644 --- a/asset-transfer-basic/application-go/go.mod +++ b/asset-transfer-basic/application-go/go.mod @@ -5,6 +5,6 @@ go 1.14 require ( github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/asset-transfer-basic/application-go/go.sum b/asset-transfer-basic/application-go/go.sum index 64e35e00..48f3fb99 100644 --- a/asset-transfer-basic/application-go/go.sum +++ b/asset-transfer-basic/application-go/go.sum @@ -159,6 +159,7 @@ github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -181,6 +182,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -194,6 +197,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -214,6 +219,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -222,6 +229,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -233,6 +242,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-basic/chaincode-go/go.mod b/asset-transfer-basic/chaincode-go/go.mod index 7a306490..8bd5b807 100644 --- a/asset-transfer-basic/chaincode-go/go.mod +++ b/asset-transfer-basic/chaincode-go/go.mod @@ -8,5 +8,5 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/asset-transfer-basic/chaincode-go/go.sum b/asset-transfer-basic/chaincode-go/go.sum index 4a64c265..8f77beba 100644 --- a/asset-transfer-basic/chaincode-go/go.sum +++ b/asset-transfer-basic/chaincode-go/go.sum @@ -101,6 +101,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -109,6 +110,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -119,6 +122,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -136,6 +141,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -143,6 +150,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -153,6 +162,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-ledger-queries/chaincode-go/go.mod b/asset-transfer-ledger-queries/chaincode-go/go.mod index 7f6d5c34..be502390 100644 --- a/asset-transfer-ledger-queries/chaincode-go/go.mod +++ b/asset-transfer-ledger-queries/chaincode-go/go.mod @@ -6,5 +6,5 @@ require ( github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/asset-transfer-ledger-queries/chaincode-go/go.sum b/asset-transfer-ledger-queries/chaincode-go/go.sum index 488f925a..8e47ea22 100644 --- a/asset-transfer-ledger-queries/chaincode-go/go.sum +++ b/asset-transfer-ledger-queries/chaincode-go/go.sum @@ -102,6 +102,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -110,6 +111,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -120,6 +123,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -137,6 +142,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -144,6 +151,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -154,6 +163,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/asset-transfer-private-data/chaincode-go/go.mod b/asset-transfer-private-data/chaincode-go/go.mod index 24bf449c..afefc574 100644 --- a/asset-transfer-private-data/chaincode-go/go.mod +++ b/asset-transfer-private-data/chaincode-go/go.mod @@ -16,7 +16,7 @@ require ( github.com/rogpeppe/go-internal v1.6.0 // indirect github.com/stretchr/testify v1.5.1 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986 // indirect google.golang.org/grpc v1.30.0 // indirect diff --git a/asset-transfer-private-data/chaincode-go/go.sum b/asset-transfer-private-data/chaincode-go/go.sum index 0bf7e8ad..1d92cad3 100644 --- a/asset-transfer-private-data/chaincode-go/go.sum +++ b/asset-transfer-private-data/chaincode-go/go.sum @@ -131,6 +131,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -142,6 +143,8 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -155,6 +158,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -175,6 +180,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -182,6 +189,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -194,6 +203,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/asset-transfer-secured-agreement/chaincode-go/go.mod b/asset-transfer-secured-agreement/chaincode-go/go.mod index e9cfa7e0..267e7edd 100644 --- a/asset-transfer-secured-agreement/chaincode-go/go.mod +++ b/asset-transfer-secured-agreement/chaincode-go/go.mod @@ -6,5 +6,5 @@ require ( github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-chaincode-go v0.0.0-20200128192331-2d899240a7ed github.com/hyperledger/fabric-contract-api-go v1.0.0 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/asset-transfer-secured-agreement/chaincode-go/go.sum b/asset-transfer-secured-agreement/chaincode-go/go.sum index 685cf666..9ba17e79 100644 --- a/asset-transfer-secured-agreement/chaincode-go/go.sum +++ b/asset-transfer-secured-agreement/chaincode-go/go.sum @@ -100,6 +100,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -108,6 +109,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -118,6 +121,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -135,6 +140,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -142,6 +149,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -153,6 +162,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/auction-dutch/application-javascript/package.json b/auction-dutch/application-javascript/package.json index 7966b24c..8846027b 100644 --- a/auction-dutch/application-javascript/package.json +++ b/auction-dutch/application-javascript/package.json @@ -11,7 +11,6 @@ "license": "Apache-2.0", "scripts": { "lint": "eslint *.js" - }, "dependencies": { "fabric-ca-client": "^2.2.4", diff --git a/auction-dutch/chaincode-go/go.mod b/auction-dutch/chaincode-go/go.mod index e679aba1..105bd90b 100644 --- a/auction-dutch/chaincode-go/go.mod +++ b/auction-dutch/chaincode-go/go.mod @@ -7,6 +7,6 @@ require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20201119163726-f8ef75b17719 github.com/hyperledger/fabric-contract-api-go v1.1.1 github.com/hyperledger/fabric-protos-go v0.0.0-20210127161553-4f432a78f286 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/auction-dutch/chaincode-go/go.sum b/auction-dutch/chaincode-go/go.sum index 0171140d..23fe3d0d 100644 --- a/auction-dutch/chaincode-go/go.sum +++ b/auction-dutch/chaincode-go/go.sum @@ -113,6 +113,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -121,6 +122,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -131,6 +134,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -148,6 +153,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -155,6 +162,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -165,6 +174,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/auction-simple/chaincode-go/go.mod b/auction-simple/chaincode-go/go.mod index 934863e6..dac4777e 100644 --- a/auction-simple/chaincode-go/go.mod +++ b/auction-simple/chaincode-go/go.mod @@ -5,5 +5,5 @@ go 1.15 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20200728190242-9b3ae92d8664 github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/auction-simple/chaincode-go/go.sum b/auction-simple/chaincode-go/go.sum index 949f6c87..00ef7542 100644 --- a/auction-simple/chaincode-go/go.sum +++ b/auction-simple/chaincode-go/go.sum @@ -102,6 +102,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -110,6 +111,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -120,6 +123,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -137,6 +142,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -144,6 +151,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -154,6 +163,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/commercial-paper/organization/digibank/contract-go/go.mod b/commercial-paper/organization/digibank/contract-go/go.mod index 534664a1..f0392654 100644 --- a/commercial-paper/organization/digibank/contract-go/go.mod +++ b/commercial-paper/organization/digibank/contract-go/go.mod @@ -7,7 +7,7 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/mailru/easyjson v0.7.0 // indirect github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect google.golang.org/grpc v1.24.0 // indirect ) diff --git a/commercial-paper/organization/digibank/contract-go/go.sum b/commercial-paper/organization/digibank/contract-go/go.sum index d84263c8..d031d7d8 100644 --- a/commercial-paper/organization/digibank/contract-go/go.sum +++ b/commercial-paper/organization/digibank/contract-go/go.sum @@ -102,8 +102,7 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -113,8 +112,8 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -124,10 +123,10 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -142,31 +141,29 @@ golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/commercial-paper/organization/magnetocorp/contract-go/go.mod b/commercial-paper/organization/magnetocorp/contract-go/go.mod index c81701b9..2e8b42cb 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/go.mod +++ b/commercial-paper/organization/magnetocorp/contract-go/go.mod @@ -7,7 +7,7 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/mailru/easyjson v0.7.0 // indirect github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect google.golang.org/grpc v1.24.0 // indirect ) diff --git a/commercial-paper/organization/magnetocorp/contract-go/go.sum b/commercial-paper/organization/magnetocorp/contract-go/go.sum index d84263c8..e4b2153e 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/go.sum +++ b/commercial-paper/organization/magnetocorp/contract-go/go.sum @@ -104,6 +104,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -115,6 +116,8 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -128,6 +131,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -148,6 +153,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -155,6 +162,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -167,6 +176,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/high-throughput/application-go/go.mod b/high-throughput/application-go/go.mod index 0529e002..b605c1ba 100644 --- a/high-throughput/application-go/go.mod +++ b/high-throughput/application-go/go.mod @@ -5,6 +5,6 @@ go 1.14 require ( github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/high-throughput/application-go/go.sum b/high-throughput/application-go/go.sum index 64e35e00..48f3fb99 100644 --- a/high-throughput/application-go/go.sum +++ b/high-throughput/application-go/go.sum @@ -159,6 +159,7 @@ github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -181,6 +182,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -194,6 +197,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -214,6 +219,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -222,6 +229,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -233,6 +242,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/high-throughput/chaincode-go/go.mod b/high-throughput/chaincode-go/go.mod index d8e7e674..47151e2d 100644 --- a/high-throughput/chaincode-go/go.mod +++ b/high-throughput/chaincode-go/go.mod @@ -5,6 +5,6 @@ go 1.12 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect ) diff --git a/high-throughput/chaincode-go/go.sum b/high-throughput/chaincode-go/go.sum index 73459fee..d94be8a9 100644 --- a/high-throughput/chaincode-go/go.sum +++ b/high-throughput/chaincode-go/go.sum @@ -31,6 +31,7 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -39,6 +40,8 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -50,6 +53,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -66,12 +71,16 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -83,6 +92,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/token-erc-1155/chaincode-go/go.mod b/token-erc-1155/chaincode-go/go.mod index 98331bbe..b9133a46 100644 --- a/token-erc-1155/chaincode-go/go.mod +++ b/token-erc-1155/chaincode-go/go.mod @@ -4,5 +4,5 @@ go 1.16 require ( github.com/hyperledger/fabric-contract-api-go v1.1.1 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/token-erc-1155/chaincode-go/go.sum b/token-erc-1155/chaincode-go/go.sum index 81e30b4a..6544df42 100644 --- a/token-erc-1155/chaincode-go/go.sum +++ b/token-erc-1155/chaincode-go/go.sum @@ -101,6 +101,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -109,6 +110,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -119,6 +122,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -136,6 +141,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -143,6 +150,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -153,6 +162,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/token-erc-20/chaincode-go/go.mod b/token-erc-20/chaincode-go/go.mod index 2d8fd89d..230de7cf 100644 --- a/token-erc-20/chaincode-go/go.mod +++ b/token-erc-20/chaincode-go/go.mod @@ -4,5 +4,5 @@ go 1.14 require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/token-erc-20/chaincode-go/go.sum b/token-erc-20/chaincode-go/go.sum index 4a64c265..8f77beba 100644 --- a/token-erc-20/chaincode-go/go.sum +++ b/token-erc-20/chaincode-go/go.sum @@ -101,6 +101,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -109,6 +110,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -119,6 +122,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -136,6 +141,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -143,6 +150,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -153,6 +162,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/token-utxo/chaincode-go/go.mod b/token-utxo/chaincode-go/go.mod index 03f30d88..d94e24d7 100644 --- a/token-utxo/chaincode-go/go.mod +++ b/token-utxo/chaincode-go/go.mod @@ -4,5 +4,5 @@ go 1.14 require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.7 // indirect + golang.org/x/tools v0.1.8 // indirect ) diff --git a/token-utxo/chaincode-go/go.sum b/token-utxo/chaincode-go/go.sum index 4a64c265..8f77beba 100644 --- a/token-utxo/chaincode-go/go.sum +++ b/token-utxo/chaincode-go/go.sum @@ -101,6 +101,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -109,6 +110,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -119,6 +122,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -136,6 +141,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -143,6 +150,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -153,6 +162,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= From f151039f8a8f6662666d58cc6db1f7fcbf83f33a Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Thu, 9 Dec 2021 10:20:52 +0000 Subject: [PATCH 038/106] Updates to asset-transfer-basic Gateway sample to align with docs (#553) Also install goimports globally to run the linting check rather than installing to each gomodule, which was causing dependency conflicts. Signed-off-by: Mark S. Lewis --- asset-transfer-abac/chaincode-go/go.mod | 5 +- asset-transfer-abac/chaincode-go/go.sum | 46 +--- .../package.json | 41 +--- .../application-gateway-typescript/src/app.ts | 205 +++++++----------- asset-transfer-basic/application-go/go.mod | 7 +- asset-transfer-basic/application-go/go.sum | 49 +---- asset-transfer-basic/chaincode-go/go.mod | 1 - asset-transfer-basic/chaincode-go/go.sum | 46 +--- .../chaincode-go/go.mod | 1 - .../chaincode-go/go.sum | 46 +--- .../chaincode-go/go.mod | 14 -- .../chaincode-go/go.sum | 93 ++------ .../chaincode-go/go.mod | 1 - .../chaincode-go/go.sum | 46 +--- auction-dutch/chaincode-go/go.mod | 2 - auction-dutch/chaincode-go/go.sum | 47 +--- auction-simple/chaincode-go/go.mod | 1 - auction-simple/chaincode-go/go.sum | 46 +--- chaincode/marbles02/go/go.mod | 4 - chaincode/marbles02/go/go.sum | 27 +-- chaincode/marbles02_private/go/go.mod | 5 +- chaincode/marbles02_private/go/go.sum | 20 -- chaincode/sacc/go.mod | 4 - chaincode/sacc/go.sum | 27 +-- ci/scripts/lint.sh | 3 +- .../organization/digibank/contract-go/go.mod | 5 - .../organization/digibank/contract-go/go.sum | 58 +---- .../magnetocorp/contract-go/go.mod | 5 - .../magnetocorp/contract-go/go.sum | 72 +----- high-throughput/application-go/go.mod | 4 +- high-throughput/application-go/go.sum | 30 --- high-throughput/chaincode-go/go.mod | 2 - high-throughput/chaincode-go/go.sum | 66 +----- interest_rate_swaps/chaincode/go.mod | 4 - interest_rate_swaps/chaincode/go.sum | 27 +-- token-erc-1155/chaincode-go/go.mod | 5 +- token-erc-1155/chaincode-go/go.sum | 46 +--- token-erc-20/chaincode-go/go.mod | 5 +- token-erc-20/chaincode-go/go.sum | 46 +--- token-utxo/chaincode-go/go.mod | 5 +- token-utxo/chaincode-go/go.sum | 46 +--- 41 files changed, 177 insertions(+), 1036 deletions(-) diff --git a/asset-transfer-abac/chaincode-go/go.mod b/asset-transfer-abac/chaincode-go/go.mod index 84a55d36..4144e4cb 100644 --- a/asset-transfer-abac/chaincode-go/go.mod +++ b/asset-transfer-abac/chaincode-go/go.mod @@ -2,7 +2,4 @@ module github.com/hyperledger/fabric-samples/asset-transfer-abac/chaincode-go go 1.15 -require ( - github.com/hyperledger/fabric-contract-api-go v1.1.1 - golang.org/x/tools v0.1.8 // indirect -) +require github.com/hyperledger/fabric-contract-api-go v1.1.1 diff --git a/asset-transfer-abac/chaincode-go/go.sum b/asset-transfer-abac/chaincode-go/go.sum index 6544df42..8ff9fad9 100644 --- a/asset-transfer-abac/chaincode-go/go.sum +++ b/asset-transfer-abac/chaincode-go/go.sum @@ -99,75 +99,35 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/asset-transfer-basic/application-gateway-typescript/package.json b/asset-transfer-basic/application-gateway-typescript/package.json index 014caa7f..8952037f 100644 --- a/asset-transfer-basic/application-gateway-typescript/package.json +++ b/asset-transfer-basic/application-gateway-typescript/package.json @@ -5,48 +5,27 @@ "main": "dist/index.js", "typings": "dist/index.d.ts", "engines": { - "node": ">=14", - "npm": ">=5" + "node": ">=14" }, "scripts": { - "lint": "eslint . --ext .ts", - "pretest": "npm run lint", - "start": "npm run build && node dist/app.js", "build": "tsc", "build:watch": "tsc -w", - "prepublishOnly": "npm run build" + "lint": "eslint . --ext .ts", + "prepare": "npm run build", + "pretest": "npm run lint", + "start": "node dist/app.js" }, "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", "dependencies": { - "@hyperledger/fabric-gateway": "unstable" + "@hyperledger/fabric-gateway": "^1.0.0" }, "devDependencies": { "@tsconfig/node14": "^1.0.1", - "@typescript-eslint/eslint-plugin": "^4.31.2", - "@typescript-eslint/parser": "^4.31.2", - "eslint": "^7.32.0", - "typescript": "^3.1.6" - }, - "nyc": { - "extension": [ - ".ts", - ".tsx" - ], - "exclude": [ - "coverage/**", - "dist/**" - ], - "reporter": [ - "text-summary", - "html" - ], - "all": true, - "check-coverage": true, - "statements": 100, - "branches": 100, - "functions": 100, - "lines": 100 + "@typescript-eslint/eslint-plugin": "^5.6.0", + "@typescript-eslint/parser": "^5.6.0", + "eslint": "^8.4.1", + "typescript": "~4.5.2" } } diff --git a/asset-transfer-basic/application-gateway-typescript/src/app.ts b/asset-transfer-basic/application-gateway-typescript/src/app.ts index 31751e33..c13ec871 100644 --- a/asset-transfer-basic/application-gateway-typescript/src/app.ts +++ b/asset-transfer-basic/application-gateway-typescript/src/app.ts @@ -5,88 +5,35 @@ */ import * as grpc from '@grpc/grpc-js'; +import { connect, Contract, Identity, Signer, signers } from '@hyperledger/fabric-gateway'; import * as crypto from 'crypto'; -import { connect, Identity, Signer, signers ,Contract} from '@hyperledger/fabric-gateway'; import { promises as fs } from 'fs'; import * as path from 'path'; +import { TextDecoder } from 'util'; const channelName = 'mychannel'; const chaincodeName = 'basic'; const mspId = 'Org1MSP'; -// path to crypto materials -const cryptoPath = path.resolve( - __dirname, - '..', - '..', - '..', - 'test-network', - 'organizations', - 'peerOrganizations', - 'org1.example.com', -); +// Path to crypto materials. +const cryptoPath = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com'); -//path to user private key directory -const keyDirectoryPath = path.resolve( - cryptoPath, - 'users', - 'User1@org1.example.com', - 'msp', - 'keystore' -); -//path to user certificate -const certPath = path.resolve( - cryptoPath, - 'users', - 'User1@org1.example.com', - 'msp', - 'signcerts', - 'cert.pem', -); -//path to peer tls certificate -const tlsCertPath = path.resolve( - cryptoPath, - 'peers', - 'peer0.org1.example.com', - 'tls', - 'ca.crt', -); +// Path to user private key directory. +const keyDirectoryPath = path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'keystore'); -//Gateway peer endpoint +// Path to user certificate. +const certPath = path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'signcerts', 'cert.pem'); + +// Path to peer tls certificate. +const tlsCertPath = path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt'); + +// Gateway peer endpoint. const peerEndpoint = 'localhost:7051'; -// pre-requisites: -// - fabric-sample two organization test-network setup with two peers and ordering service and and 2 certificate authorities -// ===> from directory /fabric-samples/test-network -// ./network.sh up createChannel -// - Use any of the asset-transfer-basic chaincodes deployed on the channel "mychannel" -// with the chaincode name of "basic". The following deploy command will package, -// install, approve, and commit the javascript chaincode, all the actions it takes -// to deploy a chaincode to a channel. -// ===> from directory /fabric-samples/test-network -// ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript -// - Be sure that node.js is installed -// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript -// node -v -// - npm installed code dependencies -// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript -// npm install -// - to run this test application -// ===> from directory /fabric-samples/asset-transfer-basic/application-typescript -// npm start +const utf8Decoder = new TextDecoder(); -/** - * A test application to show basic queries operations with any of the asset-transfer-basic chaincodes - * -- How to submit a transaction - * -- How to query and check the results - * - * To see the SDK workings, try setting the logging to show on the console before running - * export HFC_LOGGING='{"debug":"console"}' - */ - -async function main():Promise { - - // The gRPC client connection should be shared by all Gateway connections to this endpoint +async function main(): Promise { + // The gRPC client connection should be shared by all Gateway connections to this endpoint. const client = await newGrpcConnection(); const gateway = connect({ @@ -96,36 +43,33 @@ async function main():Promise { }); try { - - // Build a network instance based on the channel where the smart contract is deployed + // Get a network instance representing the channel where the smart contract is deployed. const network = gateway.getNetwork(channelName); - // Get the contract from the network. + // Get the smart contract from the network. const contract = network.getContract(chaincodeName); - // Initialize a set of asset data on the channel using the chaincode 'InitLedger' function. + // Initialize a set of asset data on the ledger using the chaincode 'InitLedger' function. await initLedger(contract); - //Return all the current assets on the ledger. + // Return all the current assets on the ledger. await getAllAssets(contract); - //Create new asset on the ledger. + // Create a new asset on the ledger. await createAsset(contract); - //Update an existing asset asynchronously. + // Update an existing asset asynchronously. await updateAssetAsync(contract); - //Get the asset details by assetID + // Get the asset details by assetID. await readAssetByID(contract); - //Update an asset which does not exist. + // Update an asset which does not exist. await updateNonExistentAsset(contract) - } finally { gateway.close(); client.close(); } - } main().catch(error => console.error('******** FAILED to run the application:', error)); @@ -133,8 +77,7 @@ main().catch(error => console.error('******** FAILED to run the application:', e async function newGrpcConnection(): Promise { const tlsRootCert = await fs.readFile(tlsCertPath); const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); - const GrpcClient = grpc.makeGenericClientConstructor({}, ''); - return new GrpcClient(peerEndpoint, tlsCredentials, { + return new grpc.Client(peerEndpoint, tlsCredentials, { 'grpc.ssl_target_name_override': 'peer0.org1.example.com', }); } @@ -146,88 +89,95 @@ async function newIdentity(): Promise { async function newSigner(): Promise { const files = await fs.readdir(keyDirectoryPath); - const privateKeyPem = await fs.readFile(path.resolve(keyDirectoryPath,files[0])); + const keyPath = path.resolve(keyDirectoryPath, files[0]); + const privateKeyPem = await fs.readFile(keyPath); const privateKey = crypto.createPrivateKey(privateKeyPem); return signers.newPrivateKeySigner(privateKey); } +/** + * This type of transaction would typically only be run once by an application the first time it was started after its + * initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function. + */ +async function initLedger(contract: Contract): Promise { + console.log('\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger'); -async function initLedger(contract:Contract):Promise { - // This type of transaction would only be run once by an application the first time it was started after it - // deployed the first time. Any updates to the chaincode deployed later would likely not need to run - // an "init" type function. - - console.log( - '\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger', - ); - - // Submit a transaction, blocking until the transaction has been committed on the ledger await contract.submitTransaction('InitLedger'); - console.log('*** Result: committed'); - + console.log('*** Transaction committed successfully'); } -async function getAllAssets(contract:Contract):Promise { - console.log( - '\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger', - ); - const result = await contract.evaluateTransaction('GetAllAssets'); - console.log(`*** Result: ${Buffer.from(result).toString()}`); +/** + * Evaluate a transaction to query ledger state. + */ +async function getAllAssets(contract: Contract): Promise { + console.log('\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger'); + + const resultBytes = await contract.evaluateTransaction('GetAllAssets'); + + const resultJson = utf8Decoder.decode(resultBytes); + const result = JSON.parse(resultJson); + console.log('*** Result:', result); } -async function createAsset(contract:Contract):Promise { - console.log( - '\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments', - ); +/** + * Submit a transaction synchronously, blocking until it has been committed to the ledger. + */ +async function createAsset(contract: Contract): Promise { + console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments'); + + const assetId = `asset${Date.now()}`; await contract.submitTransaction( 'CreateAsset', - 'asset13', + assetId, 'yellow', '5', 'Tom', '1300', ); - console.log('*** Result: committed'); + + console.log('*** Transaction committed successfully'); } -async function updateAssetAsync(contract:Contract):Promise { - - // Submit transaction asynchronously, blocking until the transaction has been sent to the orderer, and allowing - // this thread to process the chaincode response (e.g. update a UI) without waiting for the commit notification +/** + * Submit transaction asynchronously, allowing the application to process the smart contract response (e.g. update a UI) + * while waiting for the commit notification. + */ +async function updateAssetAsync(contract: Contract): Promise { + console.log('\n--> Async Submit Transaction: UpdateAsset, updates existing asset with ID, color, owner, size, and appraisedValue arguments'); const commit = await contract.submitAsync('UpdateAsset', { arguments: ['asset1', 'blue', '5', 'Tomoko', '400'], }); + console.log('*** Transaction submitted successfully'); console.log('*** Waiting for transaction commit'); - const status = await commit.getStatus(); if (!status.successful) { throw new Error(`Transaction ${status.transactionId} failed to commit with status code ${status.code}`); } console.log('*** Transaction committed successfully'); - } -async function readAssetByID(contract:Contract):Promise { - console.log( - '\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes', - ); - const result = await contract.evaluateTransaction('ReadAsset', 'asset1'); - console.log(`*** Result: ${Buffer.from(result).toString()}`); +async function readAssetByID(contract: Contract): Promise { + console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes'); + const resultBytes = await contract.evaluateTransaction('ReadAsset', 'asset1'); + + const resultJson = utf8Decoder.decode(resultBytes); + const result = JSON.parse(resultJson); + console.log('*** Result:', result); } -async function updateNonExistentAsset(contract:Contract):Promise{ +/** + * submitTransaction() will throw an error containing details of any error responses from the smart contract. + */ +async function updateNonExistentAsset(contract: Contract): Promise{ + console.log('\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error'); + try { - // How about we try a transaction where the executing chaincode throws an error - // Notice how the submitTransaction will throw an error containing the error thrown by the chaincode - console.log( - '\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error', - ); await contract.submitTransaction( 'UpdateAsset', 'asset70', @@ -238,9 +188,6 @@ async function updateNonExistentAsset(contract:Contract):Promise{ ); console.log('******** FAILED to return an error'); } catch (error) { - console.log(`*** Successfully caught the error: \n ${error}`); + console.log('*** Successfully caught the error: \n', error); } } - - - diff --git a/asset-transfer-basic/application-go/go.mod b/asset-transfer-basic/application-go/go.mod index 85e1bc42..dad8228a 100644 --- a/asset-transfer-basic/application-go/go.mod +++ b/asset-transfer-basic/application-go/go.mod @@ -2,9 +2,4 @@ module asset-transfer-basic go 1.14 -require ( - github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/tools v0.1.8 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect -) +require github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 diff --git a/asset-transfer-basic/application-go/go.sum b/asset-transfer-basic/application-go/go.sum index 48f3fb99..2cbdd369 100644 --- a/asset-transfer-basic/application-go/go.sum +++ b/asset-transfer-basic/application-go/go.sum @@ -157,9 +157,6 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -171,19 +168,13 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -191,63 +182,33 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/asset-transfer-basic/chaincode-go/go.mod b/asset-transfer-basic/chaincode-go/go.mod index 8bd5b807..a39adb01 100644 --- a/asset-transfer-basic/chaincode-go/go.mod +++ b/asset-transfer-basic/chaincode-go/go.mod @@ -8,5 +8,4 @@ require ( github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.8 // indirect ) diff --git a/asset-transfer-basic/chaincode-go/go.sum b/asset-transfer-basic/chaincode-go/go.sum index 8f77beba..5a92905b 100644 --- a/asset-transfer-basic/chaincode-go/go.sum +++ b/asset-transfer-basic/chaincode-go/go.sum @@ -99,75 +99,35 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/asset-transfer-ledger-queries/chaincode-go/go.mod b/asset-transfer-ledger-queries/chaincode-go/go.mod index be502390..fc82521a 100644 --- a/asset-transfer-ledger-queries/chaincode-go/go.mod +++ b/asset-transfer-ledger-queries/chaincode-go/go.mod @@ -6,5 +6,4 @@ require ( github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.8 // indirect ) diff --git a/asset-transfer-ledger-queries/chaincode-go/go.sum b/asset-transfer-ledger-queries/chaincode-go/go.sum index 8e47ea22..1c4ebdfb 100644 --- a/asset-transfer-ledger-queries/chaincode-go/go.sum +++ b/asset-transfer-ledger-queries/chaincode-go/go.sum @@ -100,75 +100,35 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/asset-transfer-private-data/chaincode-go/go.mod b/asset-transfer-private-data/chaincode-go/go.mod index afefc574..9026461d 100644 --- a/asset-transfer-private-data/chaincode-go/go.mod +++ b/asset-transfer-private-data/chaincode-go/go.mod @@ -3,23 +3,9 @@ module github.com/hyperledger/fabric-samples/asset-transfer-private-data/chainco go 1.14 require ( - github.com/go-openapi/jsonreference v0.19.4 // indirect - github.com/go-openapi/spec v0.19.8 // indirect - github.com/go-openapi/swag v0.19.9 // indirect - github.com/gobuffalo/envy v1.9.0 // indirect - github.com/gobuffalo/packd v1.0.0 // indirect - github.com/golang/protobuf v1.4.2 // indirect github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 - github.com/mailru/easyjson v0.7.1 // indirect - github.com/rogpeppe/go-internal v1.6.0 // indirect github.com/stretchr/testify v1.5.1 - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - golang.org/x/tools v0.1.8 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986 // indirect - google.golang.org/grpc v1.30.0 // indirect google.golang.org/protobuf v1.25.0 - gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/asset-transfer-private-data/chaincode-go/go.sum b/asset-transfer-private-data/chaincode-go/go.sum index 1d92cad3..772f26c4 100644 --- a/asset-transfer-private-data/chaincode-go/go.sum +++ b/asset-transfer-private-data/chaincode-go/go.sum @@ -8,7 +8,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -17,48 +16,40 @@ github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2A github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg= -github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg= -github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE= -github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.9.0 h1:eZR0DuEgVLfeIb1zIKt3bT4YovIMf9O9LXQeCZLXpqE= -github.com/gobuffalo/envy v1.9.0/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM= -github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI= github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -90,9 +81,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= -github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -100,10 +90,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.6.0 h1:IZRgg4sfrDH7nsAD1Y/Nwj+GzIfEwpJSLjCaNC3SbsI= -github.com/rogpeppe/go-internal v1.6.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -121,30 +109,21 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -152,19 +131,12 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -172,25 +144,11 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -198,41 +156,26 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986 h1:10ohwcLf82I55O/aQxYqmWKoOdNbQTYYComeP1KDOS4= -google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -241,9 +184,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/asset-transfer-secured-agreement/chaincode-go/go.mod b/asset-transfer-secured-agreement/chaincode-go/go.mod index 267e7edd..4f36be90 100644 --- a/asset-transfer-secured-agreement/chaincode-go/go.mod +++ b/asset-transfer-secured-agreement/chaincode-go/go.mod @@ -6,5 +6,4 @@ require ( github.com/golang/protobuf v1.3.2 github.com/hyperledger/fabric-chaincode-go v0.0.0-20200128192331-2d899240a7ed github.com/hyperledger/fabric-contract-api-go v1.0.0 - golang.org/x/tools v0.1.8 // indirect ) diff --git a/asset-transfer-secured-agreement/chaincode-go/go.sum b/asset-transfer-secured-agreement/chaincode-go/go.sum index 9ba17e79..e2949e95 100644 --- a/asset-transfer-secured-agreement/chaincode-go/go.sum +++ b/asset-transfer-secured-agreement/chaincode-go/go.sum @@ -98,76 +98,36 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/auction-dutch/chaincode-go/go.mod b/auction-dutch/chaincode-go/go.mod index 105bd90b..abc86bf5 100644 --- a/auction-dutch/chaincode-go/go.mod +++ b/auction-dutch/chaincode-go/go.mod @@ -7,6 +7,4 @@ require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20201119163726-f8ef75b17719 github.com/hyperledger/fabric-contract-api-go v1.1.1 github.com/hyperledger/fabric-protos-go v0.0.0-20210127161553-4f432a78f286 - golang.org/x/tools v0.1.8 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/auction-dutch/chaincode-go/go.sum b/auction-dutch/chaincode-go/go.sum index 23fe3d0d..26364a16 100644 --- a/auction-dutch/chaincode-go/go.sum +++ b/auction-dutch/chaincode-go/go.sum @@ -111,76 +111,37 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/auction-simple/chaincode-go/go.mod b/auction-simple/chaincode-go/go.mod index dac4777e..26f43afa 100644 --- a/auction-simple/chaincode-go/go.mod +++ b/auction-simple/chaincode-go/go.mod @@ -5,5 +5,4 @@ go 1.15 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20200728190242-9b3ae92d8664 github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.8 // indirect ) diff --git a/auction-simple/chaincode-go/go.sum b/auction-simple/chaincode-go/go.sum index 00ef7542..c4ec5f00 100644 --- a/auction-simple/chaincode-go/go.sum +++ b/auction-simple/chaincode-go/go.sum @@ -100,75 +100,35 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/chaincode/marbles02/go/go.mod b/chaincode/marbles02/go/go.mod index d61ab3ec..8daf0824 100644 --- a/chaincode/marbles02/go/go.mod +++ b/chaincode/marbles02/go/go.mod @@ -5,8 +5,4 @@ go 1.12 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022 - golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect - golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect - golang.org/x/text v0.3.2 // indirect - google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect ) diff --git a/chaincode/marbles02/go/go.sum b/chaincode/marbles02/go/go.sum index afd17d88..c2194408 100644 --- a/chaincode/marbles02/go/go.sum +++ b/chaincode/marbles02/go/go.sum @@ -30,42 +30,24 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -73,5 +55,4 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/chaincode/marbles02_private/go/go.mod b/chaincode/marbles02_private/go/go.mod index 1f91ffc3..86745398 100644 --- a/chaincode/marbles02_private/go/go.mod +++ b/chaincode/marbles02_private/go/go.mod @@ -2,7 +2,4 @@ module github.com/hyperledger/fabric-samples/chaincode/marbles02_private/go go 1.13 -require ( - github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.5 // indirect -) +require github.com/hyperledger/fabric-contract-api-go v1.1.0 diff --git a/chaincode/marbles02_private/go/go.sum b/chaincode/marbles02_private/go/go.sum index 8ea59aab..5a92905b 100644 --- a/chaincode/marbles02_private/go/go.sum +++ b/chaincode/marbles02_private/go/go.sum @@ -99,26 +99,19 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -127,27 +120,14 @@ golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/chaincode/sacc/go.mod b/chaincode/sacc/go.mod index f9deb8a7..0f41df7d 100644 --- a/chaincode/sacc/go.mod +++ b/chaincode/sacc/go.mod @@ -5,8 +5,4 @@ go 1.12 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022 - golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect - golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect - golang.org/x/text v0.3.2 // indirect - google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect ) diff --git a/chaincode/sacc/go.sum b/chaincode/sacc/go.sum index afd17d88..c2194408 100644 --- a/chaincode/sacc/go.sum +++ b/chaincode/sacc/go.sum @@ -30,42 +30,24 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -73,5 +55,4 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/ci/scripts/lint.sh b/ci/scripts/lint.sh index 89312345..5cdb8ab0 100755 --- a/ci/scripts/lint.sh +++ b/ci/scripts/lint.sh @@ -8,13 +8,14 @@ function print() { echo -e "${GREEN}${1}${NC}" } +go install golang.org/x/tools/cmd/goimports@latest + dirs=("$(find . -name "*-go" -o -name "*-java" -o -name "*-javascript" -o -name "*-typescript")") for dir in $dirs; do if [[ -d $dir ]] && [[ ! $dir =~ node_modules ]]; then print "Linting $dir" pushd $dir if [[ "$dir" =~ "-go" ]]; then - go get golang.org/x/tools/cmd/goimports print "Running go vet" go vet ./... print "Running gofmt" diff --git a/commercial-paper/organization/digibank/contract-go/go.mod b/commercial-paper/organization/digibank/contract-go/go.mod index f0392654..657af444 100644 --- a/commercial-paper/organization/digibank/contract-go/go.mod +++ b/commercial-paper/organization/digibank/contract-go/go.mod @@ -3,11 +3,6 @@ module github.com/hyperledger/fabric-samples/commercial-paper/organization/digib go 1.13 require ( - github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/hyperledger/fabric-contract-api-go v1.1.0 - github.com/mailru/easyjson v0.7.0 // indirect github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.8 // indirect - google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect - google.golang.org/grpc v1.24.0 // indirect ) diff --git a/commercial-paper/organization/digibank/contract-go/go.sum b/commercial-paper/organization/digibank/contract-go/go.sum index d031d7d8..081cf84f 100644 --- a/commercial-paper/organization/digibank/contract-go/go.sum +++ b/commercial-paper/organization/digibank/contract-go/go.sum @@ -19,9 +19,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -66,9 +65,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -102,82 +100,41 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo= -google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= @@ -186,5 +143,4 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/commercial-paper/organization/magnetocorp/contract-go/go.mod b/commercial-paper/organization/magnetocorp/contract-go/go.mod index 2e8b42cb..6c915fbb 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/go.mod +++ b/commercial-paper/organization/magnetocorp/contract-go/go.mod @@ -3,11 +3,6 @@ module github.com/hyperledger/fabric-samples/commercial-paper/organization/magne go 1.13 require ( - github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/hyperledger/fabric-contract-api-go v1.1.0 - github.com/mailru/easyjson v0.7.0 // indirect github.com/stretchr/testify v1.5.1 - golang.org/x/tools v0.1.8 // indirect - google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect - google.golang.org/grpc v1.24.0 // indirect ) diff --git a/commercial-paper/organization/magnetocorp/contract-go/go.sum b/commercial-paper/organization/magnetocorp/contract-go/go.sum index e4b2153e..081cf84f 100644 --- a/commercial-paper/organization/magnetocorp/contract-go/go.sum +++ b/commercial-paper/organization/magnetocorp/contract-go/go.sum @@ -19,9 +19,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -66,9 +65,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -102,96 +100,41 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo= -google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= @@ -200,5 +143,4 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/high-throughput/application-go/go.mod b/high-throughput/application-go/go.mod index b605c1ba..84552c5c 100644 --- a/high-throughput/application-go/go.mod +++ b/high-throughput/application-go/go.mod @@ -5,6 +5,8 @@ go 1.14 require ( github.com/hyperledger/fabric-sdk-go v1.0.0-rc1 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/tools v0.1.8 // indirect + golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect + golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect + golang.org/x/text v0.3.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/high-throughput/application-go/go.sum b/high-throughput/application-go/go.sum index 48f3fb99..fe048c48 100644 --- a/high-throughput/application-go/go.sum +++ b/high-throughput/application-go/go.sum @@ -157,9 +157,6 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -171,7 +168,6 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -180,10 +176,6 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -192,11 +184,6 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -204,7 +191,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -213,21 +199,13 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -237,15 +215,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= diff --git a/high-throughput/chaincode-go/go.mod b/high-throughput/chaincode-go/go.mod index 47151e2d..5c812b94 100644 --- a/high-throughput/chaincode-go/go.mod +++ b/high-throughput/chaincode-go/go.mod @@ -5,6 +5,4 @@ go 1.12 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022 - golang.org/x/tools v0.1.8 // indirect - google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect ) diff --git a/high-throughput/chaincode-go/go.sum b/high-throughput/chaincode-go/go.sum index d94be8a9..c2194408 100644 --- a/high-throughput/chaincode-go/go.sum +++ b/high-throughput/chaincode-go/go.sum @@ -29,82 +29,25 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -112,5 +55,4 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/interest_rate_swaps/chaincode/go.mod b/interest_rate_swaps/chaincode/go.mod index 9a1ce33e..b37affe2 100644 --- a/interest_rate_swaps/chaincode/go.mod +++ b/interest_rate_swaps/chaincode/go.mod @@ -5,8 +5,4 @@ go 1.12 require ( github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85 github.com/hyperledger/fabric-protos-go v0.0.0-20190821214336-621b908d5022 - golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect - golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect - golang.org/x/text v0.3.2 // indirect - google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect ) diff --git a/interest_rate_swaps/chaincode/go.sum b/interest_rate_swaps/chaincode/go.sum index afd17d88..c2194408 100644 --- a/interest_rate_swaps/chaincode/go.sum +++ b/interest_rate_swaps/chaincode/go.sum @@ -30,42 +30,24 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -73,5 +55,4 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/token-erc-1155/chaincode-go/go.mod b/token-erc-1155/chaincode-go/go.mod index b9133a46..4b49a6f6 100644 --- a/token-erc-1155/chaincode-go/go.mod +++ b/token-erc-1155/chaincode-go/go.mod @@ -2,7 +2,4 @@ module erc1155 go 1.16 -require ( - github.com/hyperledger/fabric-contract-api-go v1.1.1 - golang.org/x/tools v0.1.8 // indirect -) +require github.com/hyperledger/fabric-contract-api-go v1.1.1 diff --git a/token-erc-1155/chaincode-go/go.sum b/token-erc-1155/chaincode-go/go.sum index 6544df42..8ff9fad9 100644 --- a/token-erc-1155/chaincode-go/go.sum +++ b/token-erc-1155/chaincode-go/go.sum @@ -99,75 +99,35 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/token-erc-20/chaincode-go/go.mod b/token-erc-20/chaincode-go/go.mod index 230de7cf..6bee34ad 100644 --- a/token-erc-20/chaincode-go/go.mod +++ b/token-erc-20/chaincode-go/go.mod @@ -2,7 +2,4 @@ module github.com/hyperledger/fabric-samples/token-erc-20/chaincode-go go 1.14 -require ( - github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.8 // indirect -) +require github.com/hyperledger/fabric-contract-api-go v1.1.0 diff --git a/token-erc-20/chaincode-go/go.sum b/token-erc-20/chaincode-go/go.sum index 8f77beba..5a92905b 100644 --- a/token-erc-20/chaincode-go/go.sum +++ b/token-erc-20/chaincode-go/go.sum @@ -99,75 +99,35 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= diff --git a/token-utxo/chaincode-go/go.mod b/token-utxo/chaincode-go/go.mod index d94e24d7..9cdc693f 100644 --- a/token-utxo/chaincode-go/go.mod +++ b/token-utxo/chaincode-go/go.mod @@ -2,7 +2,4 @@ module github.com/hyperledger/fabric-samples/token-utxo/chaincode-go go 1.14 -require ( - github.com/hyperledger/fabric-contract-api-go v1.1.0 - golang.org/x/tools v0.1.8 // indirect -) +require github.com/hyperledger/fabric-contract-api-go v1.1.0 diff --git a/token-utxo/chaincode-go/go.sum b/token-utxo/chaincode-go/go.sum index 8f77beba..5a92905b 100644 --- a/token-utxo/chaincode-go/go.sum +++ b/token-utxo/chaincode-go/go.sum @@ -99,75 +99,35 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= From 06d67ecbfa137bff6dadd793f96d31f396185fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baran=20K=C4=B1l=C4=B1=C3=A7?= <36154262+kilicbaran@users.noreply.github.com> Date: Thu, 9 Dec 2021 13:21:16 +0300 Subject: [PATCH 039/106] Add acknowledgement text for erc1155 chaincode (#554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Baran Kılıç --- token-erc-1155/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/token-erc-1155/README.md b/token-erc-1155/README.md index 3298cc9e..ba9d4ae6 100644 --- a/token-erc-1155/README.md +++ b/token-erc-1155/README.md @@ -263,3 +263,7 @@ When you are finished, you can bring down the test network. This command will br ```bash ./network.sh down ``` + +## Acknowledgement + +This work has been carried out at Boğaziçi University and has received funding from the European Union’s Horizon 2020 Research and Innovation programme under Grant Agreement No. 856632. \ No newline at end of file From 9df7e9f86d07828eacd10a064ce07934a1834408 Mon Sep 17 00:00:00 2001 From: sapthasurendran <48531319+sapthasurendran@users.noreply.github.com> Date: Thu, 9 Dec 2021 17:07:38 +0530 Subject: [PATCH 040/106] Configtxlator script changes (#552) Signed-off-by: sapthasurendran --- test-network-k8s/scripts/set_anchor_peer.sh | 12 ++++++------ test-network/scripts/configUpdate.sh | 17 +++++++++-------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/test-network-k8s/scripts/set_anchor_peer.sh b/test-network-k8s/scripts/set_anchor_peer.sh index 59551f5e..80c32825 100755 --- a/test-network-k8s/scripts/set_anchor_peer.sh +++ b/test-network-k8s/scripts/set_anchor_peer.sh @@ -34,19 +34,19 @@ function create_config_update() { local modified=$2 local output=$3 - configtxlator proto_encode --input "${original}" --type common.Config > original_config.pb - configtxlator proto_encode --input "${modified}" --type common.Config > modified_config.pb + configtxlator proto_encode --input "${original}" --type common.Config --output original_config.pb + configtxlator proto_encode --input "${modified}" --type common.Config --output modified_config.pb # returns non-zero if no updates were detected between current and new config - configtxlator compute_update --channel_id "${CHANNEL_NAME}" --original original_config.pb --updated modified_config.pb > config_update.pb + configtxlator compute_update --channel_id "${CHANNEL_NAME}" --original original_config.pb --updated modified_config.pb --output config_update.pb if [ $? -ne 0 ]; then echo "Anchor peer has already been set to ${ANCHOR_PEER_HOST}:${ANCHOR_PEER_PORT} - no update required." return 1 fi - configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate > config_update.json + configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json echo '{"payload":{"header":{"channel_header":{"channel_id":"'${CHANNEL_NAME}'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json - configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope > ${output} + configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output ${output} return 0 } @@ -60,7 +60,7 @@ function create_anchor_peer_update() { jq '.channel_group.groups.Application.groups.'${CORE_PEER_LOCALMSPID}'.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "'${ANCHOR_PEER_HOST}'","port": '${ANCHOR_PEER_PORT}'}]},"version": "0"}}' config.json > modified_config.json { set +x; } 2>/dev/null - # Compute a config update, based on the differences between + # Compute a config update, based on the differences between # config.json and modified_config.json, write # it as a transaction to anchors.tx create_config_update config.json modified_config.json anchors.tx diff --git a/test-network/scripts/configUpdate.sh b/test-network/scripts/configUpdate.sh index 51cd0660..87087ac4 100755 --- a/test-network/scripts/configUpdate.sh +++ b/test-network/scripts/configUpdate.sh @@ -10,7 +10,7 @@ # fetchChannelConfig # Writes the current channel config for a given channel to a JSON file -# NOTE: this must be run in a CLI container since it requires configtxlator +# NOTE: this must be run in a CLI container since it requires configtxlator fetchChannelConfig() { ORG=$1 CHANNEL=$2 @@ -25,14 +25,15 @@ fetchChannelConfig() { infoln "Decoding config block to JSON and isolating config to ${OUTPUT}" set -x - configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config >"${OUTPUT}" + configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json + jq .data.data[0].payload.data.config config_block.json >"${OUTPUT}" { set +x; } 2>/dev/null } # createConfigUpdate # Takes an original and modified config, and produces the config update tx # which transitions between the two -# NOTE: this must be run in a CLI container since it requires configtxlator +# NOTE: this must be run in a CLI container since it requires configtxlator createConfigUpdate() { CHANNEL=$1 ORIGINAL=$2 @@ -40,12 +41,12 @@ createConfigUpdate() { OUTPUT=$4 set -x - configtxlator proto_encode --input "${ORIGINAL}" --type common.Config >original_config.pb - configtxlator proto_encode --input "${MODIFIED}" --type common.Config >modified_config.pb - configtxlator compute_update --channel_id "${CHANNEL}" --original original_config.pb --updated modified_config.pb >config_update.pb - configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate >config_update.json + configtxlator proto_encode --input "${ORIGINAL}" --type common.Config --output original_config.pb + configtxlator proto_encode --input "${MODIFIED}" --type common.Config --output modified_config.pb + configtxlator compute_update --channel_id "${CHANNEL}" --original original_config.pb --updated modified_config.pb --output config_update.pb + configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL'", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . >config_update_in_envelope.json - configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope >"${OUTPUT}" + configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output "${OUTPUT}" { set +x; } 2>/dev/null } From 72559dfbb51c8b2936a4a796accc656c19f41493 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 10 Dec 2021 08:51:21 +0000 Subject: [PATCH 041/106] More Gateway asset-transfer-basic tweaks to support docs (#556) Signed-off-by: Mark S. Lewis --- .../application-gateway-typescript/src/app.ts | 21 +++++++------ .../chaincode-external/assetTransfer.go | 31 ++++++++++++------- .../chaincode-go/chaincode/smartcontract.go | 17 +++++++--- .../chaincode/smartcontract_test.go | 4 +-- .../samples/assettransfer/AssetTransfer.java | 6 ++-- .../assettransfer/AssetTransferTest.java | 4 +-- .../chaincode-javascript/lib/assetTransfer.js | 4 ++- .../chaincode-typescript/src/assetTransfer.ts | 6 ++-- 8 files changed, 56 insertions(+), 37 deletions(-) diff --git a/asset-transfer-basic/application-gateway-typescript/src/app.ts b/asset-transfer-basic/application-gateway-typescript/src/app.ts index c13ec871..352be263 100644 --- a/asset-transfer-basic/application-gateway-typescript/src/app.ts +++ b/asset-transfer-basic/application-gateway-typescript/src/app.ts @@ -31,6 +31,7 @@ const tlsCertPath = path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', const peerEndpoint = 'localhost:7051'; const utf8Decoder = new TextDecoder(); +const assetId = `asset${Date.now()}`; async function main(): Promise { // The gRPC client connection should be shared by all Gateway connections to this endpoint. @@ -59,7 +60,7 @@ async function main(): Promise { await createAsset(contract); // Update an existing asset asynchronously. - await updateAssetAsync(contract); + await transferAssetAsync(contract); // Get the asset details by assetID. await readAssetByID(contract); @@ -124,9 +125,8 @@ async function getAllAssets(contract: Contract): Promise { * Submit a transaction synchronously, blocking until it has been committed to the ledger. */ async function createAsset(contract: Contract): Promise { - console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments'); + console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments'); - const assetId = `asset${Date.now()}`; await contract.submitTransaction( 'CreateAsset', assetId, @@ -143,14 +143,15 @@ async function createAsset(contract: Contract): Promise { * Submit transaction asynchronously, allowing the application to process the smart contract response (e.g. update a UI) * while waiting for the commit notification. */ -async function updateAssetAsync(contract: Contract): Promise { - console.log('\n--> Async Submit Transaction: UpdateAsset, updates existing asset with ID, color, owner, size, and appraisedValue arguments'); +async function transferAssetAsync(contract: Contract): Promise { + console.log('\n--> Async Submit Transaction: TransferAsset, updates existing asset owner'); - const commit = await contract.submitAsync('UpdateAsset', { - arguments: ['asset1', 'blue', '5', 'Tomoko', '400'], + const commit = await contract.submitAsync('TransferAsset', { + arguments: [assetId, 'Saptha'], }); + const oldOwner = utf8Decoder.decode(commit.getResult()); - console.log('*** Transaction submitted successfully'); + console.log(`*** Successfully submitted transaction to transfer ownership from ${oldOwner} to Saptha`); console.log('*** Waiting for transaction commit'); const status = await commit.getStatus(); @@ -162,9 +163,9 @@ async function updateAssetAsync(contract: Contract): Promise { } async function readAssetByID(contract: Contract): Promise { - console.log('\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes'); + console.log('\n--> Evaluate Transaction: ReadAsset, function returns asset attributes'); - const resultBytes = await contract.evaluateTransaction('ReadAsset', 'asset1'); + const resultBytes = await contract.evaluateTransaction('ReadAsset', assetId); const resultJson = utf8Decoder.decode(resultBytes); const result = JSON.parse(resultJson); diff --git a/asset-transfer-basic/chaincode-external/assetTransfer.go b/asset-transfer-basic/chaincode-external/assetTransfer.go index ab2b8ecd..a136975f 100644 --- a/asset-transfer-basic/chaincode-external/assetTransfer.go +++ b/asset-transfer-basic/chaincode-external/assetTransfer.go @@ -161,20 +161,27 @@ func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, return assetJSON != nil, nil } -// TransferAsset updates the owner field of asset with given id in world state. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error { +// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. +func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { asset, err := s.ReadAsset(ctx, id) if err != nil { - return err + return "", err } + oldOwner := asset.Owner asset.Owner = newOwner + assetJSON, err := json.Marshal(asset) if err != nil { - return err + return "", err } - return ctx.GetStub().PutState(id, assetJSON) + err = ctx.GetStub().PutState(id, assetJSON) + if err != nil { + return "", err + } + + return oldOwner, nil } // GetAllAssets returns all assets found in world state @@ -223,9 +230,9 @@ func main() { } server := &shim.ChaincodeServer{ - CCID: config.CCID, - Address: config.Address, - CC: chaincode, + CCID: config.CCID, + Address: config.Address, + CC: chaincode, TLSProps: getTLSProperties(), } @@ -265,9 +272,9 @@ func getTLSProperties() shim.TLSProperties { } return shim.TLSProperties{ - Disabled: tlsDisabled, - Key: keyBytes, - Cert: certBytes, + Disabled: tlsDisabled, + Key: keyBytes, + Cert: certBytes, ClientCACerts: clientCACertBytes, } } @@ -284,7 +291,7 @@ func getEnvOrDefault(env, defaultVal string) string { // cannot be parsed! func getBoolOrDefault(value string, defaultVal bool) bool { parsed, err := strconv.ParseBool(value) - if err!= nil { + if err != nil { return defaultVal } return parsed diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go index 7373ad42..55bc24d9 100644 --- a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go +++ b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go @@ -142,20 +142,27 @@ func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, return assetJSON != nil, nil } -// TransferAsset updates the owner field of asset with given id in world state. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error { +// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. +func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { asset, err := s.ReadAsset(ctx, id) if err != nil { - return err + return "", err } + oldOwner := asset.Owner asset.Owner = newOwner + assetJSON, err := json.Marshal(asset) if err != nil { - return err + return "", err } - return ctx.GetStub().PutState(id, assetJSON) + err = ctx.GetStub().PutState(id, assetJSON) + if err != nil { + return "", err + } + + return oldOwner, nil } // GetAllAssets returns all assets found in world state diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go b/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go index cb001ded..b2ddb2fc 100644 --- a/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go +++ b/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go @@ -143,11 +143,11 @@ func TestTransferAsset(t *testing.T) { chaincodeStub.GetStateReturns(bytes, nil) assetTransfer := chaincode.SmartContract{} - err = assetTransfer.TransferAsset(transactionContext, "", "") + _, err = assetTransfer.TransferAsset(transactionContext, "", "") require.NoError(t, err) chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = assetTransfer.TransferAsset(transactionContext, "", "") + _, err = assetTransfer.TransferAsset(transactionContext, "", "") require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") } diff --git a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java b/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java index fa7aba67..ac625b84 100644 --- a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java +++ b/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java @@ -185,10 +185,10 @@ public final class AssetTransfer implements ContractInterface { * @param ctx the transaction context * @param assetID the ID of the asset being transferred * @param newOwner the new owner - * @return the updated asset + * @return the old owner */ @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset TransferAsset(final Context ctx, final String assetID, final String newOwner) { + public String TransferAsset(final Context ctx, final String assetID, final String newOwner) { ChaincodeStub stub = ctx.getStub(); String assetJSON = stub.getStringState(assetID); @@ -205,7 +205,7 @@ public final class AssetTransfer implements ContractInterface { String sortedJson = genson.serialize(newAsset); stub.putStringState(assetID, sortedJson); - return newAsset; + return asset.getOwner(); } /** diff --git a/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java b/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java index cbbb172f..520bcec4 100644 --- a/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java +++ b/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java @@ -224,9 +224,9 @@ public final class AssetTransferTest { when(stub.getStringState("asset1")) .thenReturn("{ \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 5, \"owner\": \"Tomoko\", \"appraisedValue\": 300 }"); - Asset asset = contract.TransferAsset(ctx, "asset1", "Dr Evil"); + String oldOwner = contract.TransferAsset(ctx, "asset1", "Dr Evil"); - assertThat(asset).isEqualTo(new Asset("asset1", "blue", 5, "Dr Evil", 300)); + assertThat(oldOwner).isEqualTo("Tomoko"); } @Test diff --git a/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js b/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js index 22d109c8..beb87239 100644 --- a/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js +++ b/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js @@ -135,9 +135,11 @@ class AssetTransfer extends Contract { async TransferAsset(ctx, id, newOwner) { const assetString = await this.ReadAsset(ctx, id); const asset = JSON.parse(assetString); + const oldOwner = asset.Owner; asset.Owner = newOwner; // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); + ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); + return oldOwner; } // GetAllAssets returns all assets found in the world state. diff --git a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts index 586c4758..b9b6c3ff 100644 --- a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts +++ b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts @@ -135,14 +135,16 @@ export class AssetTransferContract extends Contract { return assetJSON && assetJSON.length > 0; } - // TransferAsset updates the owner field of asset with given id in the world state. + // TransferAsset updates the owner field of asset with given id in the world state, and returns the old owner. @Transaction() - public async TransferAsset(ctx: Context, id: string, newOwner: string): Promise { + public async TransferAsset(ctx: Context, id: string, newOwner: string): Promise { const assetString = await this.ReadAsset(ctx, id); const asset = JSON.parse(assetString); + const oldOwner = asset.Owner; asset.Owner = newOwner; // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); + return oldOwner; } // GetAllAssets returns all assets found in the world state. From bbf7096e44bcbc1a84318297dbd38c7295252cc1 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 21 Jun 2021 16:53:17 +0100 Subject: [PATCH 042/106] Initial commit Signed-off-by: James Taylor --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 2 files changed, 203 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 00000000..dac2b5f7 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# fabric-rest-sample +Prototype sample REST server to demonstrate good Fabric Node SDK practices From 063b21dd3faea72f9973e2e476aa1963b875f3ef Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 23 Jun 2021 18:35:08 +0100 Subject: [PATCH 043/106] Initial REST API skeleton Signed-off-by: James Taylor --- README.md | 1 + .../rest-api-typescript/.env.sample | 2 + .../rest-api-typescript/.eslintrc.json | 27 + .../rest-api-typescript/.gitignore | 15 + .../rest-api-typescript/.prettierrc.json | 3 + .../rest-api-typescript/README.md | 3 + .../rest-api-typescript/package-lock.json | 2129 +++++++++++++++++ .../rest-api-typescript/package.json | 43 + .../rest-api-typescript/src/index.ts | 19 + .../rest-api-typescript/src/server.ts | 89 + .../rest-api-typescript/tsconfig.json | 72 + 11 files changed, 2403 insertions(+) create mode 100644 asset-transfer-basic/rest-api-typescript/.env.sample create mode 100644 asset-transfer-basic/rest-api-typescript/.eslintrc.json create mode 100644 asset-transfer-basic/rest-api-typescript/.gitignore create mode 100644 asset-transfer-basic/rest-api-typescript/.prettierrc.json create mode 100644 asset-transfer-basic/rest-api-typescript/README.md create mode 100644 asset-transfer-basic/rest-api-typescript/package-lock.json create mode 100644 asset-transfer-basic/rest-api-typescript/package.json create mode 100644 asset-transfer-basic/rest-api-typescript/src/index.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/server.ts create mode 100644 asset-transfer-basic/rest-api-typescript/tsconfig.json diff --git a/README.md b/README.md index dac2b5f7..2059f1f5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # fabric-rest-sample + Prototype sample REST server to demonstrate good Fabric Node SDK practices diff --git a/asset-transfer-basic/rest-api-typescript/.env.sample b/asset-transfer-basic/rest-api-typescript/.env.sample new file mode 100644 index 00000000..ddc7fed8 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/.env.sample @@ -0,0 +1,2 @@ +LOG_LEVEL=info +NODE_ENV=production diff --git a/asset-transfer-basic/rest-api-typescript/.eslintrc.json b/asset-transfer-basic/rest-api-typescript/.eslintrc.json new file mode 100644 index 00000000..0eaa9dde --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/.eslintrc.json @@ -0,0 +1,27 @@ +{ + "env": { + "node": true, + "es2021": true + }, + "extends": [ + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module", + "project": "./tsconfig.json" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_" + } + ] + } +} diff --git a/asset-transfer-basic/rest-api-typescript/.gitignore b/asset-transfer-basic/rest-api-typescript/.gitignore new file mode 100644 index 00000000..dc7270d7 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/.gitignore @@ -0,0 +1,15 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +.env + +# Coverage directory used by tools like istanbul +coverage + +# Dependency directories +node_modules/ +jspm_packages/ + +# Compiled TypeScript files +dist diff --git a/asset-transfer-basic/rest-api-typescript/.prettierrc.json b/asset-transfer-basic/rest-api-typescript/.prettierrc.json new file mode 100644 index 00000000..8db60caa --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/asset-transfer-basic/rest-api-typescript/README.md b/asset-transfer-basic/rest-api-typescript/README.md new file mode 100644 index 00000000..d73efbdc --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/README.md @@ -0,0 +1,3 @@ +# Asset Transfer REST API Sample + +Prototype sample REST server to demonstrate good Fabric Node SDK practices diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json new file mode 100644 index 00000000..0ac2ba68 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -0,0 +1,2129 @@ +{ + "name": "asset-transfer-basic", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@hapi/bourne": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz", + "integrity": "sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", + "integrity": "sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.21.tgz", + "integrity": "sha512-gwCiEZqW6f7EoR8TTEfalyEhb1zA5jQJnRngr97+3pzMaO1RKoI1w2bw07TK72renMUVWcWS5mLI6rk1NqN0nA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@types/node": { + "version": "15.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz", + "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==", + "dev": true + }, + "@types/pino": { + "version": "6.3.8", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.8.tgz", + "integrity": "sha512-E47CmRy1FNMaCN8r0d8ECQOjXen9O0p6GGsUjLfmawlxRKosZ82WP1oWVKj+ikTkMDHxWzN5BuKmplo44ynrIg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/pino-pretty": "*", + "@types/pino-std-serializers": "*", + "@types/sonic-boom": "*" + } + }, + "@types/pino-http": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@types/pino-http/-/pino-http-5.4.1.tgz", + "integrity": "sha512-G/iRh3egjicSm6DPomAfFel0fUsuwKEd4vtLALSEohravku684VHhO3W14UibyHo7gWW0F1v4LxGR/pe27cNdA==", + "dev": true, + "requires": { + "@types/pino": "*" + } + }, + "@types/pino-pretty": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@types/pino-pretty/-/pino-pretty-4.7.0.tgz", + "integrity": "sha512-fIZ+VXf9gJoJR4tiiM7G+j/bZkPoZEfFGzA4d8tAWCTpTVyvVaBwnmdLs3wEXYpMjw8eXulrOzNCjmGHT3FgHw==", + "dev": true, + "requires": { + "@types/pino": "*" + } + }, + "@types/pino-std-serializers": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/pino-std-serializers/-/pino-std-serializers-2.4.1.tgz", + "integrity": "sha512-17XcksO47M24IVTVKPeAByWUd3Oez7EbIjXpSbzMPhXVzgjGtrOa49gKBwxH9hb8dKv58OelsWQ+A1G1l9S3wQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/sonic-boom": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@types/sonic-boom/-/sonic-boom-0.7.0.tgz", + "integrity": "sha512-AfqR0fZMoUXUNwusgXKxcE9DPlHNDHQp6nKYUd4PSRpLobF5CCevSpyTEBcVZreqaWKCnGBr9KI1fHMTttoB7A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz", + "integrity": "sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.28.0", + "@typescript-eslint/scope-manager": "4.28.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz", + "integrity": "sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.28.0", + "@typescript-eslint/types": "4.28.0", + "@typescript-eslint/typescript-estree": "4.28.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.0.tgz", + "integrity": "sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.28.0", + "@typescript-eslint/types": "4.28.0", + "@typescript-eslint/typescript-estree": "4.28.0", + "debug": "^4.3.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz", + "integrity": "sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.0", + "@typescript-eslint/visitor-keys": "4.28.0" + } + }, + "@typescript-eslint/types": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.0.tgz", + "integrity": "sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz", + "integrity": "sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.0", + "@typescript-eslint/visitor-keys": "4.28.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz", + "integrity": "sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.0", + "eslint-visitor-keys": "^2.0.0" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "args": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", + "integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==", + "dev": true, + "requires": { + "camelcase": "5.0.0", + "chalk": "2.4.2", + "leven": "2.1.0", + "mri": "1.1.4" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + } + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "dateformat": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.5.1.tgz", + "integrity": "sha512-OD0TZ+B7yP7ZgpJf5K2DIbj3FZvFvxgFUuaqA/V5zTjAtAAXZ1E8bktHxmAGs4x5b7PflqA9LeQ84Og7wYtF7Q==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz", + "integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true + }, + "eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-redact": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.1.tgz", + "integrity": "sha512-kYpn4Y/valC9MdrISg47tZOpYBNoTXKgT9GYXFpHN/jYFs+lFkPoisY+LcBODdKVMY96ATzvzsWv+ES/4Kmufw==" + }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", + "requires": { + "punycode": "^1.3.2" + } + }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatstr": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", + "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" + }, + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "helmet": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz", + "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-status-codes": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.1.4.tgz", + "integrity": "sha512-MZVIsLKGVOVE1KEnldppe6Ij+vmemMuApDfjhVSLzyYP+td0bREEYyAoIw9yFePoBXManCuBqmiNP5FqJS5Xkg==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "dev": true + }, + "joycon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.0.1.tgz", + "integrity": "sha512-SJcJNBg32dGgxhPtM0wQqxqV0ax9k/9TaUskGDSJkSFSQOEWWvQ3zzWdGQRIUry2j1zA5+ReH13t0Mf3StuVZA==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" + }, + "mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "requires": { + "mime-db": "1.48.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mri": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", + "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "pino": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/pino/-/pino-6.11.3.tgz", + "integrity": "sha512-drPtqkkSf0ufx2gaea3TryFiBHdNIdXKf5LN0hTM82SXI4xVIve2wLwNg92e1MT6m3jASLu6VO7eGY6+mmGeyw==", + "requires": { + "fast-redact": "^3.0.0", + "fast-safe-stringify": "^2.0.7", + "flatstr": "^1.0.12", + "pino-std-serializers": "^3.1.0", + "quick-format-unescaped": "^4.0.3", + "sonic-boom": "^1.0.2" + } + }, + "pino-http": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/pino-http/-/pino-http-5.5.0.tgz", + "integrity": "sha512-ZXhWeYhUisf9oZdS54XaBTrNVzZ7p61/sw0RpwCdU1vI/qdGWvSG4QUA5qU5Y5ya47ch3kM3HTcZf/QB5SCtNw==", + "requires": { + "fast-url-parser": "^1.1.3", + "pino": "^6.0.0", + "pino-std-serializers": "^2.4.0" + }, + "dependencies": { + "pino-std-serializers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.5.0.tgz", + "integrity": "sha512-wXqbqSrIhE58TdrxxlfLwU9eDhrzppQDvGhBEr1gYbzzM4KKo3Y63gSjiDXRKLVS2UOXdPNR2v+KnQgNrs+xUg==" + } + } + }, + "pino-pretty": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-5.1.0.tgz", + "integrity": "sha512-fpDU80MKP59XOWxqV8crTDjRegC2fbDsA56zTr5s1guiv6QuYHILc9x1a4+o9SNPtfmF2kQdpAZS+bIExtbELQ==", + "dev": true, + "requires": { + "@hapi/bourne": "^2.0.0", + "@types/node": "^15.3.0", + "args": "^5.0.1", + "chalk": "^4.0.0", + "dateformat": "^4.5.1", + "fast-safe-stringify": "^2.0.7", + "jmespath": "^0.15.0", + "joycon": "^3.0.0", + "pump": "^3.0.0", + "readable-stream": "^3.6.0", + "rfdc": "^1.3.0", + "split2": "^3.1.1", + "strip-json-comments": "^3.1.1" + } + }, + "pino-std-serializers": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz", + "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", + "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quick-format-unescaped": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz", + "integrity": "sha512-MaL/oqh02mhEo5m5J2rwsVL23Iw2PEaGVHgT2vFt8AAsr0lfvQA5dpXo9TPu0rz7tSBdUPgkbam0j/fj5ZM8yg==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "sonic-boom": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", + "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", + "requires": { + "atomic-sleep": "^1.0.0", + "flatstr": "^1.0.12" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", + "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json new file mode 100644 index 00000000..f02502e2 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -0,0 +1,43 @@ +{ + "name": "asset-transfer-basic", + "version": "1.0.0", + "description": "Asset Transfer Basic REST API implemented in TypeScript", + "main": "dist/index.js", + "dependencies": { + "dotenv": "^10.0.0", + "express": "^4.17.1", + "helmet": "^4.6.0", + "http-status-codes": "^2.1.4", + "pino": "^6.11.3", + "pino-http": "^5.5.0", + "source-map-support": "^0.5.19" + }, + "devDependencies": { + "@types/express": "^4.17.12", + "@types/node": "^15.12.4", + "@types/pino": "^6.3.8", + "@types/pino-http": "^5.4.1", + "@typescript-eslint/eslint-plugin": "^4.28.0", + "@typescript-eslint/parser": "^4.28.0", + "eslint": "^7.29.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^3.4.0", + "pino-pretty": "^5.0.2", + "prettier": "^2.3.1", + "rimraf": "^3.0.2", + "typescript": "^4.3.4" + }, + "scripts": { + "prebuild": "npm run lint", + "build": "tsc", + "clean": "rimraf ./dist", + "format": "prettier --write \"{src,test}/**/*.ts\"", + "lint": "eslint . --ext .ts", + "start": "node --require source-map-support/register ./dist", + "start:dev": "node --require source-map-support/register --require dotenv/config ./dist | pino-pretty", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Hyperledger", + "license": "Apache-2.0", + "private": true +} diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts new file mode 100644 index 00000000..9438d4b0 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import pino from 'pino'; + +import app from './server'; + +// TODO check any required env vars + +const logger = pino({ + level: process.env.LOG_LEVEL || 'info', +}); + +// Start the server +const port = Number(process.env.PORT || 3000); +app.listen(port, () => { + logger.info('Express server started on port: %d', port); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts new file mode 100644 index 00000000..044a5830 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -0,0 +1,89 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import helmet from 'helmet'; +import { StatusCodes, getReasonPhrase } from 'http-status-codes'; +import express, { NextFunction, Request, Response } from 'express'; +import pino from 'pino'; +import pinoMiddleware from 'pino-http'; + +const logger = pino({ + level: process.env.LOG_LEVEL || 'info', +}); + +const app = express(); +const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; + +app.use( + pinoMiddleware({ + logger, + customLogLevel: function customLogLevel(res, err) { + if ( + res.statusCode >= BAD_REQUEST && + res.statusCode < INTERNAL_SERVER_ERROR + ) { + return 'warn'; + } + + if (res.statusCode >= INTERNAL_SERVER_ERROR || err) { + return 'error'; + } + + return 'debug'; + }, + }) +); + +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); + +if (process.env.NODE_ENV === 'development') { + // TBC +} + +if (process.env.NODE_ENV === 'production') { + app.use(helmet()); +} + +// Health routes +app.get('/ready', (_req, res) => + res.status(OK).json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }) +); +app.get('/live', (_req, res) => + res.status(OK).json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }) +); + +// TODO delete me +app.get('/error', (_req, _res) => { + throw new Error('Example error'); +}); + +// TODO add asset APIs +// app.use("/api/assets", assetsRouter); + +// For everything else +app.use((_req, res) => + res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }) +); + +// Print API errors +// TBC in addition to pinoMiddleware errors? +app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => { + logger.error(err); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); +}); + +export default app; diff --git a/asset-transfer-basic/rest-api-typescript/tsconfig.json b/asset-transfer-basic/rest-api-typescript/tsconfig.json new file mode 100644 index 00000000..34391e93 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/tsconfig.json @@ -0,0 +1,72 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} From 1f8bc889cfae2d1f710307236657730c11614226 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 29 Jun 2021 14:04:49 +0100 Subject: [PATCH 044/106] Enable alwaysStrict compile option Signed-off-by: James Taylor --- asset-transfer-basic/rest-api-typescript/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asset-transfer-basic/rest-api-typescript/tsconfig.json b/asset-transfer-basic/rest-api-typescript/tsconfig.json index 34391e93..c0e23f1c 100644 --- a/asset-transfer-basic/rest-api-typescript/tsconfig.json +++ b/asset-transfer-basic/rest-api-typescript/tsconfig.json @@ -32,7 +32,7 @@ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ From 9c98450946564cea6fc660c7ce62ac818a97808c Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 29 Jun 2021 13:56:05 +0100 Subject: [PATCH 045/106] Initial asset route Signed-off-by: James Taylor --- .../rest-api-typescript/.env.sample | 2 +- .../rest-api-typescript/package-lock.json | 564 +++++++++++++++++- .../rest-api-typescript/package.json | 3 + .../scripts/generateEnv.sh | 23 + .../rest-api-typescript/src/assets.router.ts | 72 +++ .../rest-api-typescript/src/config.ts | 62 ++ .../rest-api-typescript/src/index.ts | 22 +- .../rest-api-typescript/src/logger.ts | 6 + .../rest-api-typescript/src/server.ts | 170 +++--- 9 files changed, 834 insertions(+), 90 deletions(-) create mode 100755 asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh create mode 100644 asset-transfer-basic/rest-api-typescript/src/assets.router.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/config.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/logger.ts diff --git a/asset-transfer-basic/rest-api-typescript/.env.sample b/asset-transfer-basic/rest-api-typescript/.env.sample index ddc7fed8..b8e71a8b 100644 --- a/asset-transfer-basic/rest-api-typescript/.env.sample +++ b/asset-transfer-basic/rest-api-typescript/.env.sample @@ -1,2 +1,2 @@ LOG_LEVEL=info -NODE_ENV=production +PORT=3000 diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index 0ac2ba68..63c72b89 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -89,6 +89,26 @@ } } }, + "@grpc/grpc-js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.4.tgz", + "integrity": "sha512-AxtZcm0mArQhY9z8T3TynCYVEaSKxNCa9mVhVwBCUnsuUEe8Zn94bPYYKVQSLt+hJJ1y0ukr3mUvtWfcATL/IQ==", + "requires": { + "@types/node": ">=12.12.47" + } + }, + "@grpc/proto-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.3.tgz", + "integrity": "sha512-AtMWwb7kY8DdtwIQh2hC4YFM1MzZ22lMA+gjbnCYDgICt14vX2tCa59bDrEjFyOI4LvORjpvT/UhHUdKvsX8og==", + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.1.1" + } + }, "@hapi/bourne": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz", @@ -121,6 +141,60 @@ "fastq": "^1.6.0" } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "@types/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", @@ -169,6 +243,11 @@ "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", "dev": true }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -178,8 +257,7 @@ "@types/node": { "version": "15.12.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz", - "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==", - "dev": true + "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==" }, "@types/pino": { "version": "6.3.8", @@ -251,6 +329,11 @@ "@types/node": "*" } }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, "@typescript-eslint/eslint-plugin": { "version": "4.28.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz", @@ -426,8 +509,7 @@ "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "ansi-styles": { "version": "3.2.1", @@ -495,17 +577,44 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, "atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "axios-cookiejar-support": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-1.0.1.tgz", + "integrity": "sha512-IZJxnAJ99XxiLqNeMOqrPbfR7fRyIfaoSLdPUf4AMQEGkH8URs0ghJK/xtqBsD+KsSr3pKl4DEQjCn834pHMig==", + "requires": { + "is-redirect": "^1.0.0", + "pify": "^5.0.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -542,6 +651,11 @@ "fill-range": "^7.0.1" } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -552,6 +666,20 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -615,6 +743,16 @@ } } }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -630,6 +768,11 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -670,6 +813,11 @@ "which": "^2.0.1" } }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, "dateformat": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.5.1.tgz", @@ -728,11 +876,31 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + } + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "encodeurl": { "version": "1.0.2", @@ -757,6 +925,16 @@ "ansi-colors": "^4.1.1" } }, + "env-var": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/env-var/-/env-var-7.0.1.tgz", + "integrity": "sha512-w4iTR5nongmpSgIByBhEaMvuLZOQCyzv4IUbhZnYMSKo/X8tj9E2Wdn4ikzKNFi29K78e5eT64iQkpar+nIYzw==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1008,6 +1186,51 @@ "vary": "~1.1.2" } }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, + "fabric-common": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/fabric-common/-/fabric-common-2.2.8.tgz", + "integrity": "sha512-lUOb2Sq645XcfIrtH6jMBaPiPUmFaHqMjGEK7uix1al0ITsNUUvtYD17MJfj/Pr0yhj0KjTI0FF1Ep3ZSL7kXg==", + "requires": { + "callsite": "^1.0.0", + "elliptic": "^6.5.4", + "fabric-protos": "2.2.8", + "js-sha3": "^0.8.0", + "jsrsasign": "^8.0.24", + "long": "^4.0.0", + "nconf": "^0.11.2", + "pkcs11js": "^1.0.6", + "promise-settle": "^0.3.0", + "sjcl": "^1.0.8", + "winston": "^2.4.5", + "yn": "^4.0.0" + } + }, + "fabric-network": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/fabric-network/-/fabric-network-2.2.8.tgz", + "integrity": "sha512-/kFgTtNA2jqY26HeEpti56G7dPAEef2fX3ebNfL/mAtJxA0Z0YXK3Jwd1N7wGCRRu+lriPd3a0wi7RPIgwAcCw==", + "requires": { + "fabric-common": "2.2.8", + "fabric-protos": "2.2.8", + "long": "^4.0.0", + "nano": "^9.0.3" + } + }, + "fabric-protos": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/fabric-protos/-/fabric-protos-2.2.8.tgz", + "integrity": "sha512-5e3MDLtXdsZpXs92kfTGRirIomaaQ3MaKQ59kp0y9QtYZGced4k9Donl1G3nREoBi0yy1bp45lkDnjRIOG9v+g==", + "requires": { + "@grpc/grpc-js": "^1.3.4", + "@grpc/proto-loader": "^0.6.2", + "protobufjs": "^6.11.2" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1126,6 +1349,11 @@ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, + "follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1142,12 +1370,32 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -1194,17 +1442,49 @@ "slash": "^3.0.0" } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "helmet": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz", "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==" }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -1267,6 +1547,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1281,8 +1566,7 @@ "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-glob": { "version": "4.0.1", @@ -1299,12 +1583,22 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", @@ -1317,6 +1611,11 @@ "integrity": "sha512-SJcJNBg32dGgxhPtM0wQqxqV0ax9k/9TaUskGDSJkSFSQOEWWvQ3zzWdGQRIUry2j1zA5+ReH13t0Mf3StuVZA==", "dev": true }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1345,6 +1644,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "jsrsasign": { + "version": "8.0.24", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-8.0.24.tgz", + "integrity": "sha512-u45jAyusqUpyGbFc2IbHoeE4rSkoBWQgLe/w99temHenX+GyCz4nflU5sjK7ajU1ffZTezl6le7u43Yjr/lkQg==" + }, "leven": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", @@ -1361,6 +1665,11 @@ "type-check": "~0.4.0" } }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -1379,6 +1688,11 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1437,6 +1751,16 @@ "mime-db": "1.48.0" } }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1457,17 +1781,61 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "optional": true + }, + "nano": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/nano/-/nano-9.0.3.tgz", + "integrity": "sha512-NFI8+6q5ihnozH6qK+BJ+ilnPfZzBhlUswaFgqUvSp2EN5eJ2BMxbzkYiBsN+waa+N95FculCdbneDmzLWfXaQ==", + "requires": { + "@types/tough-cookie": "^4.0.0", + "axios": "^0.21.1", + "axios-cookiejar-support": "^1.0.1", + "qs": "^6.9.4", + "tough-cookie": "^4.0.0" + }, + "dependencies": { + "qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "nconf": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.11.3.tgz", + "integrity": "sha512-iYsAuDS9pzjVMGIzJrGE0Vk3Eh8r/suJanRAnWGBd29rVS2XtSgzcAo5l6asV3e4hH2idVONHirg1efoBOslBg==", + "requires": { + "async": "^1.4.0", + "ini": "^2.0.0", + "secure-keys": "^1.0.0", + "yargs": "^16.1.1" + } + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1542,6 +1910,11 @@ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, + "pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==" + }, "pino": { "version": "6.11.3", "resolved": "https://registry.npmjs.org/pino/-/pino-6.11.3.tgz", @@ -1598,6 +1971,15 @@ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz", "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==" }, + "pkcs11js": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/pkcs11js/-/pkcs11js-1.2.5.tgz", + "integrity": "sha512-ZOCi2ZqKV6LprMmODsQKxgxnwGyy5nQ+nbI6QeS1M5B7gaH09xIcz8BomukrtyLHs/z3eQvvzy1SAFYXrYOG4w==", + "optional": true, + "requires": { + "nan": "^2.14.2" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1625,6 +2007,31 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "promise-settle": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/promise-settle/-/promise-settle-0.3.0.tgz", + "integrity": "sha1-tO/VcqHrdM95T4KM00naQKCOTpY=" + }, + "protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1634,6 +2041,11 @@ "ipaddr.js": "1.9.1" } }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1698,6 +2110,11 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -1750,6 +2167,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "secure-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz", + "integrity": "sha1-8MgtmKOxOah3aogIBQuCRDEIf8o=" + }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -1817,6 +2239,21 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sjcl": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", + "integrity": "sha512-LzIjEQ0S0DpIgnxMEayM1rq9aGwGRG4OnZhCdjx7glTaJtf4zRfpg87ImfjSJjoW9vKpagd82McDOwbRT5kQKQ==" + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -1898,6 +2335,11 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1907,7 +2349,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1935,7 +2376,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, "requires": { "ansi-regex": "^5.0.0" } @@ -2009,6 +2449,23 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2054,6 +2511,11 @@ "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", "dev": true }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2107,23 +2569,105 @@ "isexe": "^2.0.0" } }, + "winston": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", + "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + } + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + }, + "yn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-4.0.0.tgz", + "integrity": "sha512-huWiiCS4TxKc4SfgmTwW1K7JmXPPAmuXWYy4j9qjQo4+27Kni8mGhAAi1cloRWmBe2EqcLgt3IGqQoRL/MtPgg==" } } } diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index f02502e2..fabd9667 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -5,7 +5,9 @@ "main": "dist/index.js", "dependencies": { "dotenv": "^10.0.0", + "env-var": "^7.0.1", "express": "^4.17.1", + "fabric-network": "^2.2.8", "helmet": "^4.6.0", "http-status-codes": "^2.1.4", "pino": "^6.11.3", @@ -32,6 +34,7 @@ "build": "tsc", "clean": "rimraf ./dist", "format": "prettier --write \"{src,test}/**/*.ts\"", + "generateEnv": "./scripts/generateEnv.sh", "lint": "eslint . --ext .ts", "start": "node --require source-map-support/register ./dist", "start:dev": "node --require source-map-support/register --require dotenv/config ./dist | pino-pretty", diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh new file mode 100755 index 00000000..637c6307 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# +# SPDX-License-Identifier: Apache-2.0 +# + +: "${TEST_NETWORK_HOME:=../..}" +: "${CONNECTION_PROFILE_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" +: "${CERTIFICATE_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem}" +: "${PRIVATE_KEY_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk}" + +cat << ENV_END > .env +LOG_LEVEL=info + +PORT=3000 + +CONNECTION_PROFILE=$(cat ${CONNECTION_PROFILE_FILE} | jq -c .) + +CERTIFICATE="$(cat ${CERTIFICATE_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" + +PRIVATE_KEY="$(cat ${PRIVATE_KEY_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" + +ENV_END diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts new file mode 100644 index 00000000..180adaa8 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Note: this sample is intended to work with the basic asset transfer + * chaincode which imposes some constraints on what is possible here. + * + * For example, + * - There is no validation for Asset IDs + * - There are no error codes from the chaincode + * + */ + +import { Contract } from 'fabric-network'; +import { StatusCodes, getReasonPhrase } from 'http-status-codes'; +import express, { Request, Response } from 'express'; + +import { logger } from './logger'; + +const { INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; + +export const assetsRouter = express.Router(); + +assetsRouter.options('/:assetId', async (req: Request, res: Response) => { + try { + const contract: Contract = req.app.get('contract'); + + const assetId = req.params.assetId; + const data = await contract.evaluateTransaction('AssetExists', assetId); + const exists = data.toString() === 'true'; + + if (exists) { + res + .status(OK) + .set({ + Allow: 'GET,OPTIONS', + }) + .json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }); + } else { + res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + } catch (err) { + logger.error(err); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } +}); + +assetsRouter.get('/:assetId', async (req: Request, res: Response) => { + try { + const contract: Contract = req.app.get('contract'); + + const assetId = req.params.assetId; + const data = await contract.evaluateTransaction('ReadAsset', assetId); + const asset = JSON.parse(data.toString()); + + res.status(OK).json(asset); + } catch (err) { + logger.error(err); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts new file mode 100644 index 00000000..69ac9b69 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -0,0 +1,62 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as env from 'env-var'; + +export const logLevel = env + .get('LOG_LEVEL') + .default('info') + .asEnum(['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent']); + +export const port = env + .get('PORT') + .default('3000') + .example('3000') + .asIntPositive(); + +export const asLocalHost = env + .get('AS_LOCAL_HOST') + .default('true') + .example('true') + .asBoolStrict(); + +export const identityName = 'restServerIdentity'; + +export const mspId = env + .get('MSP_ID') + .default('Org1MSP') + .example('Org1MSP') + .asString(); + +export const channelName = env + .get('CHANNEL_NAME') + .default('mychannel') + .example('mychannel') + .asString(); + +export const chaincodeName = env + .get('CHAINCODE_NAME') + .default('basic') + .example('basic') + .asString(); + +export const connectionProfile = env + .get('CONNECTION_PROFILE') + .required() + .example( + '{"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... }' + ) + .asJsonObject(); + +export const certificate = env + .get('CERTIFICATE') + .required() + .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') + .asString(); + +export const privateKey = env + .get('PRIVATE_KEY') + .required() + .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') + .asString(); diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 9438d4b0..435a8022 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -2,18 +2,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -import pino from 'pino'; +import { logger } from './logger'; +import { createServer } from './server'; +import * as config from './config'; -import app from './server'; +async function main() { + const app = await createServer(); -// TODO check any required env vars + app.listen(config.port, () => { + logger.info('Express server started on port: %d', config.port); + }); +} -const logger = pino({ - level: process.env.LOG_LEVEL || 'info', -}); - -// Start the server -const port = Number(process.env.PORT || 3000); -app.listen(port, () => { - logger.info('Express server started on port: %d', port); -}); +main(); diff --git a/asset-transfer-basic/rest-api-typescript/src/logger.ts b/asset-transfer-basic/rest-api-typescript/src/logger.ts new file mode 100644 index 00000000..fe53a01e --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/logger.ts @@ -0,0 +1,6 @@ +import pino from 'pino'; +import * as config from './config'; + +export const logger = pino({ + level: config.logLevel, +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 044a5830..436f2c8e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -4,86 +4,122 @@ import helmet from 'helmet'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; -import express, { NextFunction, Request, Response } from 'express'; -import pino from 'pino'; +import express, { Application, NextFunction, Request, Response } from 'express'; import pinoMiddleware from 'pino-http'; +import { Gateway, GatewayOptions, Contract, Wallets } from 'fabric-network'; -const logger = pino({ - level: process.env.LOG_LEVEL || 'info', -}); +import * as config from './config'; +import { logger } from './logger'; +import { assetsRouter } from './assets.router'; -const app = express(); const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; -app.use( - pinoMiddleware({ - logger, - customLogLevel: function customLogLevel(res, err) { - if ( - res.statusCode >= BAD_REQUEST && - res.statusCode < INTERNAL_SERVER_ERROR - ) { - return 'warn'; - } +export const createServer = async (): Promise => { + const app = express(); - if (res.statusCode >= INTERNAL_SERVER_ERROR || err) { - return 'error'; - } + app.use( + pinoMiddleware({ + logger, + customLogLevel: function customLogLevel(res, err) { + if ( + res.statusCode >= BAD_REQUEST && + res.statusCode < INTERNAL_SERVER_ERROR + ) { + return 'warn'; + } - return 'debug'; - }, - }) -); + if (res.statusCode >= INTERNAL_SERVER_ERROR || err) { + return 'error'; + } -app.use(express.json()); -app.use(express.urlencoded({ extended: true })); + return 'debug'; + }, + }) + ); -if (process.env.NODE_ENV === 'development') { - // TBC -} + app.use(express.json()); + app.use(express.urlencoded({ extended: true })); -if (process.env.NODE_ENV === 'production') { - app.use(helmet()); -} + if (process.env.NODE_ENV === 'development') { + // TBC + } -// Health routes -app.get('/ready', (_req, res) => - res.status(OK).json({ - status: getReasonPhrase(OK), - timestamp: new Date().toISOString(), - }) -); -app.get('/live', (_req, res) => - res.status(OK).json({ - status: getReasonPhrase(OK), - timestamp: new Date().toISOString(), - }) -); + if (process.env.NODE_ENV === 'production') { + app.use(helmet()); + } -// TODO delete me -app.get('/error', (_req, _res) => { - throw new Error('Example error'); -}); + const contract = await getContract(); + app.set('contract', contract); -// TODO add asset APIs -// app.use("/api/assets", assetsRouter); + // Health routes + app.get('/ready', (_req, res) => + res.status(OK).json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }) + ); + app.get('/live', (_req, res) => + res.status(OK).json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }) + ); -// For everything else -app.use((_req, res) => - res.status(NOT_FOUND).json({ - status: getReasonPhrase(NOT_FOUND), - timestamp: new Date().toISOString(), - }) -); - -// Print API errors -// TBC in addition to pinoMiddleware errors? -app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => { - logger.error(err); - return res.status(INTERNAL_SERVER_ERROR).json({ - status: getReasonPhrase(INTERNAL_SERVER_ERROR), - timestamp: new Date().toISOString(), + // TODO delete me + app.get('/error', (_req, _res) => { + throw new Error('Example error'); }); -}); -export default app; + app.use('/api/assets', assetsRouter); + + // For everything else + app.use((_req, res) => + res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }) + ); + + // Print API errors + // TBC in addition to pinoMiddleware errors? + app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => { + logger.error(err); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + }); + + return app; +}; + +// TODO should this go in a fabric.ts file? + +const getContract = async (): Promise => { + const wallet = await Wallets.newInMemoryWallet(); + + const x509Identity = { + credentials: { + certificate: config.certificate, + privateKey: config.privateKey, + }, + mspId: config.mspId, + type: 'X.509', + }; + await wallet.put(config.identityName, x509Identity); + + const gateway = new Gateway(); + + const gatewayOpts: GatewayOptions = { + wallet, + identity: config.identityName, + discovery: { enabled: true, asLocalhost: config.asLocalHost }, + }; + + await gateway.connect(config.connectionProfile, gatewayOpts); + + const network = await gateway.getNetwork(config.channelName); + const contract = network.getContract(config.chaincodeName); + + return contract; +}; From 324f1c8683fb8297ff1ae8bb9e7bfd129ac21a1b Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 2 Jul 2021 12:24:13 +0100 Subject: [PATCH 046/106] Specify query handler strategy Avoid load on a single peer by specifying the PREFER_MSPID_SCOPE_ROUND_ROBIN strategy Signed-off-by: James Taylor --- .../rest-api-typescript/src/fabric.ts | 46 +++++++++++++++++++ .../rest-api-typescript/src/server.ts | 34 +------------- 2 files changed, 47 insertions(+), 33 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/fabric.ts diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts new file mode 100644 index 00000000..a568b376 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + DefaultQueryHandlerStrategies, + Gateway, + GatewayOptions, + Contract, + Wallets, +} from 'fabric-network'; + +import * as config from './config'; + +export const getContract = async (): Promise => { + const wallet = await Wallets.newInMemoryWallet(); + + const x509Identity = { + credentials: { + certificate: config.certificate, + privateKey: config.privateKey, + }, + mspId: config.mspId, + type: 'X.509', + }; + await wallet.put(config.identityName, x509Identity); + + const gateway = new Gateway(); + + const connectOptions: GatewayOptions = { + wallet, + identity: config.identityName, + discovery: { enabled: true, asLocalhost: config.asLocalHost }, + queryHandlerOptions: { + timeout: 3, + strategy: DefaultQueryHandlerStrategies.PREFER_MSPID_SCOPE_ROUND_ROBIN, + }, + }; + + await gateway.connect(config.connectionProfile, connectOptions); + + const network = await gateway.getNetwork(config.channelName); + const contract = network.getContract(config.chaincodeName); + + return contract; +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 436f2c8e..19714d0e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -6,11 +6,10 @@ import helmet from 'helmet'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import express, { Application, NextFunction, Request, Response } from 'express'; import pinoMiddleware from 'pino-http'; -import { Gateway, GatewayOptions, Contract, Wallets } from 'fabric-network'; -import * as config from './config'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; +import { getContract } from './fabric'; const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; @@ -92,34 +91,3 @@ export const createServer = async (): Promise => { return app; }; - -// TODO should this go in a fabric.ts file? - -const getContract = async (): Promise => { - const wallet = await Wallets.newInMemoryWallet(); - - const x509Identity = { - credentials: { - certificate: config.certificate, - privateKey: config.privateKey, - }, - mspId: config.mspId, - type: 'X.509', - }; - await wallet.put(config.identityName, x509Identity); - - const gateway = new Gateway(); - - const gatewayOpts: GatewayOptions = { - wallet, - identity: config.identityName, - discovery: { enabled: true, asLocalhost: config.asLocalHost }, - }; - - await gateway.connect(config.connectionProfile, gatewayOpts); - - const network = await gateway.getNetwork(config.channelName); - const contract = network.getContract(config.chaincodeName); - - return contract; -}; From 3b50404763cb484e1988fd75e64cdc1457b2167b Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 2 Jul 2021 12:13:15 +0100 Subject: [PATCH 047/106] Initial create asset logic Signed-off-by: James Taylor --- .../rest-api-typescript/.env.sample | 21 ++ .../rest-api-typescript/package-lock.json | 108 ++++++++ .../rest-api-typescript/package.json | 4 + .../scripts/generateEnv.sh | 20 +- .../rest-api-typescript/src/assets.router.ts | 98 +++++++- .../rest-api-typescript/src/config.ts | 49 +++- .../rest-api-typescript/src/fabric.ts | 230 +++++++++++++++++- .../rest-api-typescript/src/index.ts | 14 +- .../rest-api-typescript/src/redis.ts | 16 ++ .../rest-api-typescript/src/server.ts | 2 + 10 files changed, 542 insertions(+), 20 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/redis.ts diff --git a/asset-transfer-basic/rest-api-typescript/.env.sample b/asset-transfer-basic/rest-api-typescript/.env.sample index b8e71a8b..9fe7cf46 100644 --- a/asset-transfer-basic/rest-api-typescript/.env.sample +++ b/asset-transfer-basic/rest-api-typescript/.env.sample @@ -1,2 +1,23 @@ LOG_LEVEL=info + PORT=3000 + +RETRY_DELAY=3000 + +HLF_CONNECTION_PROFILE={"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... } + +HLF_CERTIFICATE="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" + +HLF_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" + +HLF_COMMIT_TIMEOUT=3000 + +HLF_ENDORSE_TIMEOUT=30 + +REDIS_HOST=localhost + +REDIS_PORT=6379 + +#REDIS_USERNAME= + +#REDIS_PASSWORD= diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index 63c72b89..4c4d1114 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -237,6 +237,15 @@ "@types/range-parser": "*" } }, + "@types/ioredis": { + "version": "4.26.4", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.26.4.tgz", + "integrity": "sha512-QFbjNq7EnOGw6d1gZZt2h26OFXjx7z+eqEnbCHSrDI1OOLEgOHMKdtIajJbuCr9uO+X9kQQRe7Lz6uxqxl5XKg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/json-schema": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", @@ -753,6 +762,11 @@ "wrap-ansi": "^7.0.0" } }, + "cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -838,6 +852,11 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "denque": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -1186,6 +1205,15 @@ "vary": "~1.1.2" } }, + "express-validator": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.12.0.tgz", + "integrity": "sha512-lcQAdVeAO+pBbHD33nIsDsd+QPakLX08tJ82iEsXj6ezyWCfYjE9RY/g9SVq5z4G0NaIkH8039Oe4r0G92DRyA==", + "requires": { + "lodash": "^4.17.21", + "validator": "^13.5.2" + } + }, "eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", @@ -1552,6 +1580,38 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" }, + "ioredis": { + "version": "4.27.6", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.27.6.tgz", + "integrity": "sha512-6W3ZHMbpCa8ByMyC1LJGOi7P2WiOKP9B3resoZOVLDhi+6dDBOW+KNsRq3yI36Hmnb2sifCxHX+YSarTeXh48A==", + "requires": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1665,6 +1725,11 @@ "type-check": "~0.4.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -1676,6 +1741,16 @@ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -1867,6 +1942,11 @@ "word-wrap": "^1.2.3" } }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2104,6 +2184,24 @@ "util-deprecate": "^1.0.1" } }, + "redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "^1.0.0" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2340,6 +2438,11 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -2555,6 +2658,11 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "validator": { + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", + "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index fabd9667..cfee92bd 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -7,15 +7,18 @@ "dotenv": "^10.0.0", "env-var": "^7.0.1", "express": "^4.17.1", + "express-validator": "^6.12.0", "fabric-network": "^2.2.8", "helmet": "^4.6.0", "http-status-codes": "^2.1.4", + "ioredis": "^4.27.6", "pino": "^6.11.3", "pino-http": "^5.5.0", "source-map-support": "^0.5.19" }, "devDependencies": { "@types/express": "^4.17.12", + "@types/ioredis": "^4.26.4", "@types/node": "^15.12.4", "@types/pino": "^6.3.8", "@types/pino-http": "^5.4.1", @@ -38,6 +41,7 @@ "lint": "eslint . --ext .ts", "start": "node --require source-map-support/register ./dist", "start:dev": "node --require source-map-support/register --require dotenv/config ./dist | pino-pretty", + "start:redis": "docker run -p 6379:6379 --name fabric-sample-redis -d redis", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Hyperledger", diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index 637c6307..fa30cbdc 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -14,10 +14,24 @@ LOG_LEVEL=info PORT=3000 -CONNECTION_PROFILE=$(cat ${CONNECTION_PROFILE_FILE} | jq -c .) +RETRY_DELAY=3000 -CERTIFICATE="$(cat ${CERTIFICATE_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" +HLF_CONNECTION_PROFILE=$(cat ${CONNECTION_PROFILE_FILE} | jq -c .) -PRIVATE_KEY="$(cat ${PRIVATE_KEY_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" +HLF_CERTIFICATE="$(cat ${CERTIFICATE_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" + +HLF_PRIVATE_KEY="$(cat ${PRIVATE_KEY_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" + +HLF_COMMIT_TIMEOUT=3000 + +HLF_ENDORSE_TIMEOUT=30 + +REDIS_HOST=localhost + +REDIS_PORT=6379 + +#REDIS_USERNAME= + +#REDIS_PASSWORD= ENV_END diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 180adaa8..f3ad92e1 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -10,17 +10,101 @@ * */ -import { Contract } from 'fabric-network'; -import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import express, { Request, Response } from 'express'; - +import { body, validationResult } from 'express-validator'; +import { Contract } from 'fabric-network'; +import { getReasonPhrase, StatusCodes } from 'http-status-codes'; +import { Redis } from 'ioredis'; +import { + clearTransactionDetails, + createDeferredEventHandler, + storeTransactionDetails, +} from './fabric'; import { logger } from './logger'; -const { INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; +const { ACCEPTED, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = + StatusCodes; export const assetsRouter = express.Router(); +assetsRouter.post( + '/', + body('id', 'must be a string').notEmpty(), + body('color', 'must be a string').notEmpty(), + body('size', 'must be a number').isNumeric(), + body('owner', 'must be a string').notEmpty(), + body('appraisedValue', 'must be a number').isNumeric(), + async (req: Request, res: Response) => { + logger.info(req.body, 'Create asset request received'); + + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + timestamp: new Date().toISOString(), + errors: errors.array(), + }); + } + + const contract: Contract = req.app.get('contract'); + const redis: Redis = req.app.get('redis'); + const txn = contract.createTransaction('CreateAsset'); + const txnId = txn.getTransactionId(); + const txnState = txn.serialize(); + const txnArgs = JSON.stringify([ + req.body.id, + req.body.color, + req.body.size, + req.body.owner, + req.body.appraisedValue, + ]); + + try { + const timestamp = Date.now(); + + // Store the transaction details and set the event handler in case there + // are problems later with commiting the transaction + await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); + txn.setEventHandler(createDeferredEventHandler(redis)); + + await txn.submit( + req.body.id, + req.body.color, + req.body.size, + req.body.owner, + req.body.appraisedValue + ); + + return res.status(ACCEPTED).json({ + status: getReasonPhrase(ACCEPTED), + timestamp: new Date().toISOString(), + }); + } catch (err) { + // TODO will this always catch endorsement errors or can those + // arrive later? + + // There's no point retrying a transaction if there were business + // logic errors so clear the transaction details + // + // Note: it would be nice to pick out business logic errors returned + // from chaincode, e.g. asset already exists, and return those as a + // 400 error with message instead. Unfortunately the asset transfer + // sample or Fabric Node SDK do not provide any well defined error + // codes that can be checked. + await clearTransactionDetails(redis, txnId); + + logger.error(err); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); + assetsRouter.options('/:assetId', async (req: Request, res: Response) => { + logger.info(req.body, 'Read asset request received'); + try { const contract: Contract = req.app.get('contract'); @@ -29,7 +113,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { const exists = data.toString() === 'true'; if (exists) { - res + return res .status(OK) .set({ Allow: 'GET,OPTIONS', @@ -39,7 +123,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { timestamp: new Date().toISOString(), }); } else { - res.status(NOT_FOUND).json({ + return res.status(NOT_FOUND).json({ status: getReasonPhrase(NOT_FOUND), timestamp: new Date().toISOString(), }); @@ -61,7 +145,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { const data = await contract.evaluateTransaction('ReadAsset', assetId); const asset = JSON.parse(data.toString()); - res.status(OK).json(asset); + return res.status(OK).json(asset); } catch (err) { logger.error(err); return res.status(INTERNAL_SERVER_ERROR).json({ diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 69ac9b69..cf967dcf 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -15,6 +15,12 @@ export const port = env .example('3000') .asIntPositive(); +export const retryDelay = env + .get('RETRY_DELAY') + .default('3000') + .example('3000') + .asIntPositive(); + export const asLocalHost = env .get('AS_LOCAL_HOST') .default('true') @@ -24,25 +30,37 @@ export const asLocalHost = env export const identityName = 'restServerIdentity'; export const mspId = env - .get('MSP_ID') + .get('HLF_MSP_ID') .default('Org1MSP') .example('Org1MSP') .asString(); export const channelName = env - .get('CHANNEL_NAME') + .get('HLF_CHANNEL_NAME') .default('mychannel') .example('mychannel') .asString(); export const chaincodeName = env - .get('CHAINCODE_NAME') + .get('HLF_CHAINCODE_NAME') .default('basic') .example('basic') .asString(); +export const commitTimeout = env + .get('HLF_COMMIT_TIMEOUT') + .default('3000') + .example('3000') + .asIntPositive(); + +export const endorseTimeout = env + .get('HLF_ENDORSE_TIMEOUT') + .default('30') + .example('30') + .asIntPositive(); + export const connectionProfile = env - .get('CONNECTION_PROFILE') + .get('HLF_CONNECTION_PROFILE') .required() .example( '{"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... }' @@ -50,13 +68,32 @@ export const connectionProfile = env .asJsonObject(); export const certificate = env - .get('CERTIFICATE') + .get('HLF_CERTIFICATE') .required() .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') .asString(); export const privateKey = env - .get('PRIVATE_KEY') + .get('HLF_PRIVATE_KEY') .required() .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') .asString(); + +export const redisHost = env + .get('REDIS_HOST') + .default('localhost') + .example('localhost') + .asString(); + +export const redisPort = env + .get('REDIS_PORT') + .default('6379') + .example('6379') + .asIntPositive(); + +export const redisUsername = env + .get('REDIS_USERNAME') + .example('conga') + .asString(); + +export const redisPassword = env.get('REDIS_PASSWORD').asString(); diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index a568b376..95db6b8b 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -3,14 +3,19 @@ */ import { + CommitListener, + Contract, + DefaultEventHandlerStrategies, DefaultQueryHandlerStrategies, Gateway, GatewayOptions, - Contract, + TxEventHandler, + TxEventHandlerFactory, Wallets, } from 'fabric-network'; - +import { Redis } from 'ioredis'; import * as config from './config'; +import { logger } from './logger'; export const getContract = async (): Promise => { const wallet = await Wallets.newInMemoryWallet(); @@ -31,6 +36,11 @@ export const getContract = async (): Promise => { wallet, identity: config.identityName, discovery: { enabled: true, asLocalhost: config.asLocalHost }, + eventHandlerOptions: { + commitTimeout: config.commitTimeout, + endorseTimeout: config.endorseTimeout, + strategy: DefaultEventHandlerStrategies.PREFER_MSPID_SCOPE_ANYFORTX, + }, queryHandlerOptions: { timeout: 3, strategy: DefaultQueryHandlerStrategies.PREFER_MSPID_SCOPE_ROUND_ROBIN, @@ -44,3 +54,219 @@ export const getContract = async (): Promise => { return contract; }; + +export const createDeferredEventHandler = ( + redis: Redis +): TxEventHandlerFactory => { + return (transactionId, network): TxEventHandler => { + // TODO would like to store the transaction details here + // but doesn't seem possible to use await or handle errors + // in the TxEventHandlerFactory :( + + const mspId = network.getGateway().getIdentity().mspId; + const peers = network.getChannel().getEndorsers(mspId); + + const options = Object.assign( + { + commitTimeout: 30, + }, + network.getGateway().getOptions().eventHandlerOptions + ); + + const removeCommitListener = async () => { + network.removeCommitListener(listener); + logger.info('Stopped listening for transaction %s events', transactionId); + + const txnExists = await redis.exists(transactionId); + if (txnExists) { + logger.warn( + 'Transaction %s was not successfully committed', + transactionId + ); + } + }; + + const listener: CommitListener = async (error, event) => { + if (error) { + logger.error(error, 'Commit error for transaction %s', transactionId); + } + + if (event && event.isValid) { + logger.info('Transaction %s successfully committed', transactionId); + + await clearTransactionDetails(redis, transactionId); + await removeCommitListener(); + } + }; + + const deferredEventHandler: TxEventHandler = { + startListening: async () => { + logger.info('Setting timeout for %d ms', options.commitTimeout * 1000); + setTimeout(async () => { + logger.info( + 'Timeout listening for transaction %s events', + transactionId + ); + await removeCommitListener(); + }, options.commitTimeout * 1000); + + await network.addCommitListener(listener, peers, transactionId); + logger.info('Listening for transaction %s events', transactionId); + }, + waitForEvents: async () => { + // No-op + }, + cancelListening: async () => { + // TODO this is what the doc says, but is it true?! + logger.info( + 'Submission of transaction %s to the orderer failed', + transactionId + ); + await removeCommitListener(); + }, + }; + + return deferredEventHandler; + }; +}; + +export const startRetryLoop = (contract: Contract, redis: Redis): void => { + setInterval( + async (redis) => { + try { + const pendingTransactionCount = await (redis as Redis).zcard( + 'index:txn:timestamp' + ); + logger.info('Transactions awaiting retry: %d', pendingTransactionCount); + + const transactionIds = await (redis as Redis).zrange( + 'index:txn:timestamp', + -1, + -1 + ); + + if (transactionIds.length > 0) { + const transactionId = transactionIds[0]; + const savedTransaction = await (redis as Redis).hgetall( + `txn:${transactionId}` + ); + + await retryTransaction( + contract, + redis, + transactionId, + savedTransaction + ); + } + } catch (err) { + // TODO just log? + logger.error(err, 'error getting saved transaction state'); + } + }, + config.retryDelay, + redis + ); +}; + +const retryTransaction = async ( + contract: Contract, + redis: Redis, + transactionId: string, + savedTransaction: Record +) => { + logger.info('Retrying transaction %s', transactionId); + + try { + const transaction = contract.deserializeTransaction( + Buffer.from(savedTransaction.state) + ); + const args: string[] = JSON.parse(savedTransaction.args); + + await transaction.submit(...args); + await clearTransactionDetails(redis, transactionId); + } catch (err) { + if (isDuplicateTransaction(err)) { + logger.info('Transaction %s has already been committed', transactionId); + await clearTransactionDetails(redis, transactionId); + } else { + // TODO check for retry limit and update timestamp + logger.warn( + err, + 'Retry %d failed for transaction %s', + savedTransaction.retries, + transactionId + ); + await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1); + } + } +}; + +const isDuplicateTransaction = (error: { + errors: { endorsements: { details: string }[] }[]; +}) => { + // TODO this is horrible! Isn't it possible to check for TxValidationCode DUPLICATE_TXID somehow? + try { + const isDuplicateTxn = error?.errors?.some((err) => + err?.endorsements?.some((endorsement) => + endorsement?.details?.startsWith('duplicate transaction found') + ) + ); + + return isDuplicateTxn; + } catch (err) { + logger.warn(err, 'error checking for duplicate transaction'); + } + + return false; +}; + +// TODO move these to redis.ts? + +export const storeTransactionDetails = async ( + redis: Redis, + transactionId: string, + transactionState: Buffer, + transactionArgs: string, + timestamp: number +): Promise => { + const key = `txn:${transactionId}`; + logger.info( + 'Storing transaction details. Key: %s State: %s Args: %s Timestamp: %d', + key, + transactionState, + transactionArgs, + timestamp + ); + await redis + .multi() + .hset( + key, + 'state', + transactionState, + 'args', + transactionArgs, + 'timestamp', + timestamp, + 'retries', + '0' + ) + .zadd('index:txn:timestamp', timestamp, transactionId) + .exec(); +}; + +export const clearTransactionDetails = async ( + redis: Redis, + transactionId: string +): Promise => { + const key = `txn:${transactionId}`; + logger.info('Removing transaction details. Key: %s', key); + try { + await redis + .multi() + .del(key) + .zrem('index:txn:timestamp', transactionId) + .exec(); + } catch (err) { + logger.error(err, 'error remove saved transaction state'); + } +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 435a8022..b91a6c3f 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -2,16 +2,26 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { Contract } from 'fabric-network'; +import { Redis } from 'ioredis'; +import * as config from './config'; +import { startRetryLoop } from './fabric'; import { logger } from './logger'; import { createServer } from './server'; -import * as config from './config'; async function main() { const app = await createServer(); + const contract: Contract = app.get('contract'); + const redis: Redis = app.get('redis'); + startRetryLoop(contract, redis); + app.listen(config.port, () => { logger.info('Express server started on port: %d', config.port); }); } -main(); +// TODO handle errors! E.g. try starting with the wrong cert and private key! +main().catch((err) => { + logger.error(err, 'Unxepected error'); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.ts b/asset-transfer-basic/rest-api-typescript/src/redis.ts new file mode 100644 index 00000000..9cc79dba --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/redis.ts @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import IORedis, { RedisOptions } from 'ioredis'; + +import * as config from './config'; + +const redisOptions: RedisOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, +}; + +export const redis = new IORedis(redisOptions); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 19714d0e..f22f5fdd 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -10,6 +10,7 @@ import pinoMiddleware from 'pino-http'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; import { getContract } from './fabric'; +import { redis } from './redis'; const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; @@ -49,6 +50,7 @@ export const createServer = async (): Promise => { const contract = await getContract(); app.set('contract', contract); + app.set('redis', redis); // Health routes app.get('/ready', (_req, res) => From d9e0de606bd5a703cff6da14281d326ad1c10625 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 13 Jul 2021 14:14:08 +0100 Subject: [PATCH 048/106] Update readme Signed-off-by: James Taylor --- README.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2059f1f5..a2dc791f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,63 @@ -# fabric-rest-sample +# Fabric REST sample Prototype sample REST server to demonstrate good Fabric Node SDK practices + +The primary aim of this sample is to show how to write a long running client application using the Fabric Node SDK + +The REST API is intended to work with the [basic asset transfer example](https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic) + +To install the basic asset transfer chaincode on a local Fabric network, follow the [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/release-2.2/test_network.html) tutorial + +To build and start the sample REST server, you'll need to [download and install an LTS version of node](https://nodejs.org/en/download/) + +Clone this repository and change to the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory before running the following commands + +Install dependencies + +```shell +npm install +``` + +Build the REST server + +```shell +npm run build +``` + +Create a `.env` file to configure the server for the test network (make sure TEST_NETWORK_HOME is set to the fully qualified `test-network` directory) + +```shell +TEST_NETWORK_HOME=$HOME/fabric-samples/test-network npm run generateEnv +``` + +Start a Redis server + +```shell +npm run start:redis +``` + +Start the sample REST server + +```shell +npm run start:dev +``` + +If everything went well, you can now make REST calls! + +For example, check whether an asset exists... + +```shell +curl -v -X OPTIONS http://localhost:3000/api/assets/asset7 +``` + +Create an asset... + +```shell +curl --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets +``` + +Get an asset... + +```shell +curl -v http://localhost:3000/api/assets/asset7 +``` From f06f1eed4b2cc90dfbfab84be038ff49f965af5d Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 14 Jul 2021 11:27:07 +0100 Subject: [PATCH 049/106] Update logging Signed-off-by: James Taylor --- .../rest-api-typescript/src/assets.router.ts | 16 +++++++----- .../rest-api-typescript/src/fabric.ts | 26 +++++++++---------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index f3ad92e1..7058aa75 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -35,7 +35,7 @@ assetsRouter.post( body('owner', 'must be a string').notEmpty(), body('appraisedValue', 'must be a number').isNumeric(), async (req: Request, res: Response) => { - logger.info(req.body, 'Create asset request received'); + logger.debug(req.body, 'Create asset request received'); const errors = validationResult(req); if (!errors.isEmpty()) { @@ -93,7 +93,7 @@ assetsRouter.post( // codes that can be checked. await clearTransactionDetails(redis, txnId); - logger.error(err); + logger.error(err, 'Error processing create asset request for asset ID %s with transaction ID %s', req.body.id, txnId); return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -103,12 +103,12 @@ assetsRouter.post( ); assetsRouter.options('/:assetId', async (req: Request, res: Response) => { - logger.info(req.body, 'Read asset request received'); + const assetId = req.params.assetId; + logger.debug('Asset options request received for asset ID %s', assetId); try { const contract: Contract = req.app.get('contract'); - const assetId = req.params.assetId; const data = await contract.evaluateTransaction('AssetExists', assetId); const exists = data.toString() === 'true'; @@ -129,7 +129,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { }); } } catch (err) { - logger.error(err); + logger.error(err, 'Error processing asset options request for asset ID %s', assetId); return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -138,16 +138,18 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { }); assetsRouter.get('/:assetId', async (req: Request, res: Response) => { + const assetId = req.params.assetId; + logger.debug('Read asset request received for asset ID %s', assetId); + try { const contract: Contract = req.app.get('contract'); - const assetId = req.params.assetId; const data = await contract.evaluateTransaction('ReadAsset', assetId); const asset = JSON.parse(data.toString()); return res.status(OK).json(asset); } catch (err) { - logger.error(err); + logger.error(err, 'Error processing read asset request for asset ID %s', assetId); return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 95db6b8b..6ce34866 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -75,7 +75,7 @@ export const createDeferredEventHandler = ( const removeCommitListener = async () => { network.removeCommitListener(listener); - logger.info('Stopped listening for transaction %s events', transactionId); + logger.debug('Stopped listening for transaction %s events', transactionId); const txnExists = await redis.exists(transactionId); if (txnExists) { @@ -92,7 +92,7 @@ export const createDeferredEventHandler = ( } if (event && event.isValid) { - logger.info('Transaction %s successfully committed', transactionId); + logger.debug('Transaction %s successfully committed', transactionId); await clearTransactionDetails(redis, transactionId); await removeCommitListener(); @@ -101,9 +101,9 @@ export const createDeferredEventHandler = ( const deferredEventHandler: TxEventHandler = { startListening: async () => { - logger.info('Setting timeout for %d ms', options.commitTimeout * 1000); + logger.debug('Setting timeout for %d ms', options.commitTimeout * 1000); setTimeout(async () => { - logger.info( + logger.debug( 'Timeout listening for transaction %s events', transactionId ); @@ -111,14 +111,14 @@ export const createDeferredEventHandler = ( }, options.commitTimeout * 1000); await network.addCommitListener(listener, peers, transactionId); - logger.info('Listening for transaction %s events', transactionId); + logger.debug('Listening for transaction %s events', transactionId); }, waitForEvents: async () => { // No-op }, cancelListening: async () => { // TODO this is what the doc says, but is it true?! - logger.info( + logger.warn( 'Submission of transaction %s to the orderer failed', transactionId ); @@ -137,7 +137,7 @@ export const startRetryLoop = (contract: Contract, redis: Redis): void => { const pendingTransactionCount = await (redis as Redis).zcard( 'index:txn:timestamp' ); - logger.info('Transactions awaiting retry: %d', pendingTransactionCount); + logger.debug('Transactions awaiting retry: %d', pendingTransactionCount); const transactionIds = await (redis as Redis).zrange( 'index:txn:timestamp', @@ -174,7 +174,7 @@ const retryTransaction = async ( transactionId: string, savedTransaction: Record ) => { - logger.info('Retrying transaction %s', transactionId); + logger.debug('Retrying transaction %s', transactionId); try { const transaction = contract.deserializeTransaction( @@ -186,7 +186,7 @@ const retryTransaction = async ( await clearTransactionDetails(redis, transactionId); } catch (err) { if (isDuplicateTransaction(err)) { - logger.info('Transaction %s has already been committed', transactionId); + logger.debug('Transaction %s has already been committed', transactionId); await clearTransactionDetails(redis, transactionId); } else { // TODO check for retry limit and update timestamp @@ -214,7 +214,7 @@ const isDuplicateTransaction = (error: { return isDuplicateTxn; } catch (err) { - logger.warn(err, 'error checking for duplicate transaction'); + logger.warn(err, 'Error checking for duplicate transaction'); } return false; @@ -230,7 +230,7 @@ export const storeTransactionDetails = async ( timestamp: number ): Promise => { const key = `txn:${transactionId}`; - logger.info( + logger.debug( 'Storing transaction details. Key: %s State: %s Args: %s Timestamp: %d', key, transactionState, @@ -259,7 +259,7 @@ export const clearTransactionDetails = async ( transactionId: string ): Promise => { const key = `txn:${transactionId}`; - logger.info('Removing transaction details. Key: %s', key); + logger.debug('Removing transaction details. Key: %s', key); try { await redis .multi() @@ -267,6 +267,6 @@ export const clearTransactionDetails = async ( .zrem('index:txn:timestamp', transactionId) .exec(); } catch (err) { - logger.error(err, 'error remove saved transaction state'); + logger.error(err, 'Error remove saved transaction state for transaction ID %s', transactionId); } }; From 8ebca62b40b46aeb11997a42a31c099d6587a378 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 14 Jul 2021 11:31:29 +0100 Subject: [PATCH 050/106] Fix lint errors Signed-off-by: James Taylor --- .../rest-api-typescript/src/assets.router.ts | 19 ++++++++++++++++--- .../rest-api-typescript/src/fabric.ts | 16 +++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 7058aa75..853e3e60 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -93,7 +93,12 @@ assetsRouter.post( // codes that can be checked. await clearTransactionDetails(redis, txnId); - logger.error(err, 'Error processing create asset request for asset ID %s with transaction ID %s', req.body.id, txnId); + logger.error( + err, + 'Error processing create asset request for asset ID %s with transaction ID %s', + req.body.id, + txnId + ); return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -129,7 +134,11 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { }); } } catch (err) { - logger.error(err, 'Error processing asset options request for asset ID %s', assetId); + logger.error( + err, + 'Error processing asset options request for asset ID %s', + assetId + ); return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -149,7 +158,11 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { return res.status(OK).json(asset); } catch (err) { - logger.error(err, 'Error processing read asset request for asset ID %s', assetId); + logger.error( + err, + 'Error processing read asset request for asset ID %s', + assetId + ); return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 6ce34866..495238f3 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -75,7 +75,10 @@ export const createDeferredEventHandler = ( const removeCommitListener = async () => { network.removeCommitListener(listener); - logger.debug('Stopped listening for transaction %s events', transactionId); + logger.debug( + 'Stopped listening for transaction %s events', + transactionId + ); const txnExists = await redis.exists(transactionId); if (txnExists) { @@ -137,7 +140,10 @@ export const startRetryLoop = (contract: Contract, redis: Redis): void => { const pendingTransactionCount = await (redis as Redis).zcard( 'index:txn:timestamp' ); - logger.debug('Transactions awaiting retry: %d', pendingTransactionCount); + logger.debug( + 'Transactions awaiting retry: %d', + pendingTransactionCount + ); const transactionIds = await (redis as Redis).zrange( 'index:txn:timestamp', @@ -267,6 +273,10 @@ export const clearTransactionDetails = async ( .zrem('index:txn:timestamp', transactionId) .exec(); } catch (err) { - logger.error(err, 'Error remove saved transaction state for transaction ID %s', transactionId); + logger.error( + err, + 'Error remove saved transaction state for transaction ID %s', + transactionId + ); } }; From 8250359db67613ce3556063de7e1984ccfd77684 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 14 Jul 2021 17:47:35 +0100 Subject: [PATCH 051/106] Add delete and put endpoints Signed-off-by: James Taylor --- README.md | 26 +++- .../rest-api-typescript/src/assets.router.ts | 144 +++++++++++++++++- 2 files changed, 168 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a2dc791f..9f004b8a 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,32 @@ Create an asset... curl --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets ``` -Get an asset... +Read an asset... ```shell curl -v http://localhost:3000/api/assets/asset7 ``` + +Update an asset... + +```shell +curl --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 +``` + +Delete an asset... + +```shell +curl -v -X DELETE http://localhost:3000/api/assets/asset7 +``` + +Or all of the above for complete chaos! + +``` +curl --request OPTIONS http://localhost:3000/api/assets/asset7 \ + --next --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets \ + --next --request READ http://localhost:3000/api/assets/asset7 \ + --next --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 \ + --next --request READ http://localhost:3000/api/assets/asset7 \ + --next --request DELETE http://localhost:3000/api/assets/asset7 \ + --next --request READ http://localhost:3000/api/assets/asset7 +``` diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 853e3e60..8711c56d 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -41,6 +41,7 @@ assetsRouter.post( if (!errors.isEmpty()) { return res.status(BAD_REQUEST).json({ status: getReasonPhrase(BAD_REQUEST), + message: 'Invalid request body', timestamp: new Date().toISOString(), errors: errors.array(), }); @@ -121,7 +122,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { return res .status(OK) .set({ - Allow: 'GET,OPTIONS', + Allow: 'DELETE,GET,OPTIONS,PUT', }) .json({ status: getReasonPhrase(OK), @@ -169,3 +170,144 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { }); } }); + +// TODO this shares a lot of code with the post endpoint! +assetsRouter.put( + '/:assetId', + body('id', 'must be a string').notEmpty(), + body('color', 'must be a string').notEmpty(), + body('size', 'must be a number').isNumeric(), + body('owner', 'must be a string').notEmpty(), + body('appraisedValue', 'must be a number').isNumeric(), + async (req: Request, res: Response) => { + logger.debug(req.body, 'Update asset request received'); + + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + message: 'Invalid request body', + timestamp: new Date().toISOString(), + errors: errors.array(), + }); + } + + if (req.params.assetId != req.body.id) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + message: 'Asset IDs must match', + timestamp: new Date().toISOString(), + }); + } + + const contract: Contract = req.app.get('contract'); + const redis: Redis = req.app.get('redis'); + const txn = contract.createTransaction('UpdateAsset'); + const txnId = txn.getTransactionId(); + const txnState = txn.serialize(); + const txnArgs = JSON.stringify([ + req.params.assetId, + req.body.color, + req.body.size, + req.body.owner, + req.body.appraisedValue, + ]); + + try { + const timestamp = Date.now(); + + // Store the transaction details and set the event handler in case there + // are problems later with commiting the transaction + await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); + txn.setEventHandler(createDeferredEventHandler(redis)); + + await txn.submit( + req.params.assetId, + req.body.color, + req.body.size, + req.body.owner, + req.body.appraisedValue + ); + + return res.status(ACCEPTED).json({ + status: getReasonPhrase(ACCEPTED), + timestamp: new Date().toISOString(), + }); + } catch (err) { + // TODO will this always catch endorsement errors or can those + // arrive later? + + // There's no point retrying a transaction if there were business + // logic errors so clear the transaction details + // + // Note: it would be nice to pick out business logic errors returned + // from chaincode, e.g. asset already exists, and return those as a + // 400 error with message instead. Unfortunately the asset transfer + // sample or Fabric Node SDK do not provide any well defined error + // codes that can be checked. + await clearTransactionDetails(redis, txnId); + + logger.error( + err, + 'Error processing update asset request for asset ID %s with transaction ID %s', + req.params.assetId, + txnId + ); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); + +assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { + logger.debug(req.body, 'Delete asset request received'); + + const contract: Contract = req.app.get('contract'); + const redis: Redis = req.app.get('redis'); + const txn = contract.createTransaction('DeleteAsset'); + const txnId = txn.getTransactionId(); + const txnState = txn.serialize(); + const txnArgs = JSON.stringify([req.params.assetId]); + + try { + const timestamp = Date.now(); + + // Store the transaction details and set the event handler in case there + // are problems later with commiting the transaction + await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); + txn.setEventHandler(createDeferredEventHandler(redis)); + + await txn.submit(req.params.assetId); + + return res.status(ACCEPTED).json({ + status: getReasonPhrase(ACCEPTED), + timestamp: new Date().toISOString(), + }); + } catch (err) { + // TODO will this always catch endorsement errors or can those + // arrive later? + + // There's no point retrying a transaction if there were business + // logic errors so clear the transaction details + // + // Note: it would be nice to pick out business logic errors returned + // from chaincode, e.g. asset already exists, and return those as a + // 400 error with message instead. Unfortunately the asset transfer + // sample or Fabric Node SDK do not provide any well defined error + // codes that can be checked. + await clearTransactionDetails(redis, txnId); + + logger.error( + err, + 'Error processing delete asset request for asset ID %s with transaction ID %s', + req.params.assetId, + txnId + ); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } +}); From d810128fcda6f6afa02dc945ce3709d90edb8b93 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 15 Jul 2021 11:23:55 +0100 Subject: [PATCH 052/106] Add patch endpoint Signed-off-by: James Taylor --- README.md | 18 ++--- .../rest-api-typescript/src/assets.router.ts | 81 ++++++++++++++++++- 2 files changed, 86 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 9f004b8a..e422210d 100644 --- a/README.md +++ b/README.md @@ -68,20 +68,14 @@ Update an asset... curl --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 ``` +Transfer an asset... + +```shell +curl --header "Content-Type: application/json" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 +``` + Delete an asset... ```shell curl -v -X DELETE http://localhost:3000/api/assets/asset7 ``` - -Or all of the above for complete chaos! - -``` -curl --request OPTIONS http://localhost:3000/api/assets/asset7 \ - --next --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets \ - --next --request READ http://localhost:3000/api/assets/asset7 \ - --next --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 \ - --next --request READ http://localhost:3000/api/assets/asset7 \ - --next --request DELETE http://localhost:3000/api/assets/asset7 \ - --next --request READ http://localhost:3000/api/assets/asset7 -``` diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 8711c56d..d4c6361c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -29,6 +29,7 @@ export const assetsRouter = express.Router(); assetsRouter.post( '/', + body().isObject().withMessage('body must contain an asset object'), body('id', 'must be a string').notEmpty(), body('color', 'must be a string').notEmpty(), body('size', 'must be a number').isNumeric(), @@ -122,7 +123,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { return res .status(OK) .set({ - Allow: 'DELETE,GET,OPTIONS,PUT', + Allow: 'DELETE,GET,OPTIONS,PATCH,PUT', }) .json({ status: getReasonPhrase(OK), @@ -174,6 +175,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { // TODO this shares a lot of code with the post endpoint! assetsRouter.put( '/:assetId', + body().isObject().withMessage('body must contain an asset object'), body('id', 'must be a string').notEmpty(), body('color', 'must be a string').notEmpty(), body('size', 'must be a number').isNumeric(), @@ -261,6 +263,83 @@ assetsRouter.put( } ); +// TODO this shares a lot of code with the post endpoint! +assetsRouter.patch( + '/:assetId', + body() + .isArray({ + min: 1, + max: 1, + }) + .withMessage('body must contain an array with a single patch operation'), + body('*.op', "operation must be 'replace'").equals('replace'), + body('*.path', "path must be '/owner'").equals('/owner'), + body('*.value', 'must be a string').isString(), + async (req: Request, res: Response) => { + logger.debug(req.body, 'Transfer asset request received'); + + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + message: 'Invalid request body', + timestamp: new Date().toISOString(), + errors: errors.array(), + }); + } + + const assetId = req.params.assetId; + const newOwner = req.body[0].value; + + const contract: Contract = req.app.get('contract'); + const redis: Redis = req.app.get('redis'); + const txn = contract.createTransaction('TransferAsset'); + const txnId = txn.getTransactionId(); + const txnState = txn.serialize(); + const txnArgs = JSON.stringify([assetId, newOwner]); + + try { + const timestamp = Date.now(); + + // Store the transaction details and set the event handler in case there + // are problems later with commiting the transaction + await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); + txn.setEventHandler(createDeferredEventHandler(redis)); + + await txn.submit(assetId, newOwner); + + return res.status(ACCEPTED).json({ + status: getReasonPhrase(ACCEPTED), + timestamp: new Date().toISOString(), + }); + } catch (err) { + // TODO will this always catch endorsement errors or can those + // arrive later? + + // There's no point retrying a transaction if there were business + // logic errors so clear the transaction details + // + // Note: it would be nice to pick out business logic errors returned + // from chaincode, e.g. asset already exists, and return those as a + // 400 error with message instead. Unfortunately the asset transfer + // sample or Fabric Node SDK do not provide any well defined error + // codes that can be checked. + await clearTransactionDetails(redis, txnId); + + logger.error( + err, + 'Error processing update asset request for asset ID %s with transaction ID %s', + req.params.assetId, + txnId + ); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); + assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { logger.debug(req.body, 'Delete asset request received'); From 400367e8a6ea488cb013a34bd1570c2a5e6dd804 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 15 Jul 2021 12:08:29 +0100 Subject: [PATCH 053/106] Add get all assets endpoint Signed-off-by: James Taylor --- README.md | 22 +++++++++++++------ .../rest-api-typescript/src/assets.router.ts | 19 ++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e422210d..24b890b0 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ The REST API is intended to work with the [basic asset transfer example](https:/ To install the basic asset transfer chaincode on a local Fabric network, follow the [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/release-2.2/test_network.html) tutorial +**Note:** these instructions should work with the release-2.2 branch of `fabric-samples` but later versions require some changes + To build and start the sample REST server, you'll need to [download and install an LTS version of node](https://nodejs.org/en/download/) Clone this repository and change to the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory before running the following commands @@ -44,38 +46,44 @@ npm run start:dev If everything went well, you can now make REST calls! -For example, check whether an asset exists... +For example, get all assets... ```shell -curl -v -X OPTIONS http://localhost:3000/api/assets/asset7 +curl http://localhost:3000/api/assets +``` + +Check whether an asset exists... + +```shell +curl --include --request OPTIONS http://localhost:3000/api/assets/asset7 ``` Create an asset... ```shell -curl --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets +curl --include --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets ``` Read an asset... ```shell -curl -v http://localhost:3000/api/assets/asset7 +curl http://localhost:3000/api/assets/asset7 ``` Update an asset... ```shell -curl --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 +curl --include --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 ``` Transfer an asset... ```shell -curl --header "Content-Type: application/json" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 +curl --include --header "Content-Type: application/json" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 ``` Delete an asset... ```shell -curl -v -X DELETE http://localhost:3000/api/assets/asset7 +curl --include --request DELETE http://localhost:3000/api/assets/asset7 ``` diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index d4c6361c..4a950636 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -27,6 +27,25 @@ const { ACCEPTED, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = export const assetsRouter = express.Router(); +assetsRouter.get('/', async (req: Request, res: Response) => { + logger.debug('Get all assets request received'); + + try { + const contract: Contract = req.app.get('contract'); + + const data = await contract.evaluateTransaction('GetAllAssets'); + const assets = JSON.parse(data.toString()); + + return res.status(OK).json(assets); + } catch (err) { + logger.error(err, 'Error processing get all assets request'); + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } +}); + assetsRouter.post( '/', body().isObject().withMessage('body must contain an asset object'), From 273fc2833a754ced2a6770b6f11a5eeb41b15767 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 15 Jul 2021 14:18:12 +0100 Subject: [PATCH 054/106] Add REST Client demo file Add demo file for use with the REST Client for Visual Studio Code Signed-off-by: James Taylor --- demo.http | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 demo.http diff --git a/demo.http b/demo.http new file mode 100644 index 00000000..bf5e0961 --- /dev/null +++ b/demo.http @@ -0,0 +1,60 @@ +// Demo file for use with REST Client for Visual Studio Code +// See https://github.com/Huachao/vscode-restclient +@hostname = localhost +@port = 3000 +@baseUrl = http://{{hostname}}:{{port}}/api + +### Get all assets + +GET {{baseUrl}}/assets HTTP/1.1 + +### Check if asset exists + +OPTIONS {{baseUrl}}/assets/asset7 HTTP/1.1 + +### Create asset + +POST {{baseUrl}}/assets HTTP/1.1 +content-type: application/json + +{ + "id": "asset7", + "color": "red", + "size": 42, + "owner": "Jean", + "appraisedValue": 101 +} + +### Read asset + +GET {{baseUrl}}/assets/asset7 HTTP/1.1 + +### Update asset + +PUT {{baseUrl}}/assets/asset7 HTTP/1.1 +content-type: application/json + +{ + "id": "asset7", + "color": "red", + "size": 11, + "owner": "Jean", + "appraisedValue": 101 +} + +### Transfer asset + +PATCH {{baseUrl}}/assets/asset7 HTTP/1.1 +content-type: application/json + +[ + { + "op": "replace", + "path": "/owner", + "value": "Ashleigh" + } +] + +### Delete asset + +DELETE {{baseUrl}}/assets/asset7 HTTP/1.1 From 60aedf1b82e31772a43a9f93f2e7f04fd11a18ff Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 15 Jul 2021 18:30:38 +0100 Subject: [PATCH 055/106] Refactor transaction logic Remove duplication and handle errors from the asset transfer smart contract Signed-off-by: James Taylor --- .gitignore | 1 + .../rest-api-typescript/src/assets.router.ts | 225 +++++++----------- .../rest-api-typescript/src/errors.ts | 33 +++ .../rest-api-typescript/src/fabric.ts | 141 ++++++----- .../rest-api-typescript/src/redis.ts | 58 ++++- 5 files changed, 266 insertions(+), 192 deletions(-) create mode 100644 .gitignore create mode 100644 asset-transfer-basic/rest-api-typescript/src/errors.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b0b21603 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +local.http diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 4a950636..f70db1e3 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -15,15 +15,18 @@ import { body, validationResult } from 'express-validator'; import { Contract } from 'fabric-network'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { Redis } from 'ioredis'; -import { - clearTransactionDetails, - createDeferredEventHandler, - storeTransactionDetails, -} from './fabric'; +import { AssetExistsError, AssetNotFoundError } from './errors'; +import { evatuateTransaction, submitTransaction } from './fabric'; import { logger } from './logger'; -const { ACCEPTED, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = - StatusCodes; +const { + ACCEPTED, + BAD_REQUEST, + CONFLICT, + INTERNAL_SERVER_ERROR, + NOT_FOUND, + OK, +} = StatusCodes; export const assetsRouter = express.Router(); @@ -33,7 +36,7 @@ assetsRouter.get('/', async (req: Request, res: Response) => { try { const contract: Contract = req.app.get('contract'); - const data = await contract.evaluateTransaction('GetAllAssets'); + const data = await evatuateTransaction(contract, 'GetAllAssets'); const assets = JSON.parse(data.toString()); return res.status(OK).json(assets); @@ -61,6 +64,7 @@ assetsRouter.post( if (!errors.isEmpty()) { return res.status(BAD_REQUEST).json({ status: getReasonPhrase(BAD_REQUEST), + reason: 'VALIDATION_ERROR', message: 'Invalid request body', timestamp: new Date().toISOString(), errors: errors.array(), @@ -69,27 +73,14 @@ assetsRouter.post( const contract: Contract = req.app.get('contract'); const redis: Redis = req.app.get('redis'); - const txn = contract.createTransaction('CreateAsset'); - const txnId = txn.getTransactionId(); - const txnState = txn.serialize(); - const txnArgs = JSON.stringify([ - req.body.id, - req.body.color, - req.body.size, - req.body.owner, - req.body.appraisedValue, - ]); + const assetId = req.body.id; try { - const timestamp = Date.now(); - - // Store the transaction details and set the event handler in case there - // are problems later with commiting the transaction - await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); - txn.setEventHandler(createDeferredEventHandler(redis)); - - await txn.submit( - req.body.id, + await submitTransaction( + contract, + redis, + 'CreateAsset', + assetId, req.body.color, req.body.size, req.body.owner, @@ -101,25 +92,22 @@ assetsRouter.post( timestamp: new Date().toISOString(), }); } catch (err) { - // TODO will this always catch endorsement errors or can those - // arrive later? - - // There's no point retrying a transaction if there were business - // logic errors so clear the transaction details - // - // Note: it would be nice to pick out business logic errors returned - // from chaincode, e.g. asset already exists, and return those as a - // 400 error with message instead. Unfortunately the asset transfer - // sample or Fabric Node SDK do not provide any well defined error - // codes that can be checked. - await clearTransactionDetails(redis, txnId); - logger.error( err, 'Error processing create asset request for asset ID %s with transaction ID %s', - req.body.id, - txnId + assetId, + err.transactionId ); + + if (err instanceof AssetExistsError) { + return res.status(CONFLICT).json({ + status: getReasonPhrase(CONFLICT), + reason: 'ASSET_EXISTS', + message: err.message, + timestamp: new Date().toISOString(), + }); + } + return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -135,7 +123,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { try { const contract: Contract = req.app.get('contract'); - const data = await contract.evaluateTransaction('AssetExists', assetId); + const data = await evatuateTransaction(contract, 'AssetExists', assetId); const exists = data.toString() === 'true'; if (exists) { @@ -174,7 +162,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { try { const contract: Contract = req.app.get('contract'); - const data = await contract.evaluateTransaction('ReadAsset', assetId); + const data = await evatuateTransaction(contract, 'ReadAsset', assetId); const asset = JSON.parse(data.toString()); return res.status(OK).json(asset); @@ -184,6 +172,14 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { 'Error processing read asset request for asset ID %s', assetId ); + + if (err instanceof AssetNotFoundError) { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -191,7 +187,6 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { } }); -// TODO this shares a lot of code with the post endpoint! assetsRouter.put( '/:assetId', body().isObject().withMessage('body must contain an asset object'), @@ -207,6 +202,7 @@ assetsRouter.put( if (!errors.isEmpty()) { return res.status(BAD_REQUEST).json({ status: getReasonPhrase(BAD_REQUEST), + reason: 'VALIDATION_ERROR', message: 'Invalid request body', timestamp: new Date().toISOString(), errors: errors.array(), @@ -216,6 +212,7 @@ assetsRouter.put( if (req.params.assetId != req.body.id) { return res.status(BAD_REQUEST).json({ status: getReasonPhrase(BAD_REQUEST), + reason: 'ASSET_ID_MISMATCH', message: 'Asset IDs must match', timestamp: new Date().toISOString(), }); @@ -223,27 +220,14 @@ assetsRouter.put( const contract: Contract = req.app.get('contract'); const redis: Redis = req.app.get('redis'); - const txn = contract.createTransaction('UpdateAsset'); - const txnId = txn.getTransactionId(); - const txnState = txn.serialize(); - const txnArgs = JSON.stringify([ - req.params.assetId, - req.body.color, - req.body.size, - req.body.owner, - req.body.appraisedValue, - ]); + const assetId = req.params.assetId; try { - const timestamp = Date.now(); - - // Store the transaction details and set the event handler in case there - // are problems later with commiting the transaction - await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); - txn.setEventHandler(createDeferredEventHandler(redis)); - - await txn.submit( - req.params.assetId, + await submitTransaction( + contract, + redis, + 'UpdateAsset', + assetId, req.body.color, req.body.size, req.body.owner, @@ -255,25 +239,20 @@ assetsRouter.put( timestamp: new Date().toISOString(), }); } catch (err) { - // TODO will this always catch endorsement errors or can those - // arrive later? - - // There's no point retrying a transaction if there were business - // logic errors so clear the transaction details - // - // Note: it would be nice to pick out business logic errors returned - // from chaincode, e.g. asset already exists, and return those as a - // 400 error with message instead. Unfortunately the asset transfer - // sample or Fabric Node SDK do not provide any well defined error - // codes that can be checked. - await clearTransactionDetails(redis, txnId); - logger.error( err, 'Error processing update asset request for asset ID %s with transaction ID %s', - req.params.assetId, - txnId + assetId, + err.transactionId ); + + if (err instanceof AssetNotFoundError) { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -282,7 +261,6 @@ assetsRouter.put( } ); -// TODO this shares a lot of code with the post endpoint! assetsRouter.patch( '/:assetId', body() @@ -301,56 +279,46 @@ assetsRouter.patch( if (!errors.isEmpty()) { return res.status(BAD_REQUEST).json({ status: getReasonPhrase(BAD_REQUEST), + reason: 'VALIDATION_ERROR', message: 'Invalid request body', timestamp: new Date().toISOString(), errors: errors.array(), }); } + const contract: Contract = req.app.get('contract'); + const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; const newOwner = req.body[0].value; - const contract: Contract = req.app.get('contract'); - const redis: Redis = req.app.get('redis'); - const txn = contract.createTransaction('TransferAsset'); - const txnId = txn.getTransactionId(); - const txnState = txn.serialize(); - const txnArgs = JSON.stringify([assetId, newOwner]); - try { - const timestamp = Date.now(); - - // Store the transaction details and set the event handler in case there - // are problems later with commiting the transaction - await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); - txn.setEventHandler(createDeferredEventHandler(redis)); - - await txn.submit(assetId, newOwner); + await submitTransaction( + contract, + redis, + 'TransferAsset', + assetId, + newOwner + ); return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), timestamp: new Date().toISOString(), }); } catch (err) { - // TODO will this always catch endorsement errors or can those - // arrive later? - - // There's no point retrying a transaction if there were business - // logic errors so clear the transaction details - // - // Note: it would be nice to pick out business logic errors returned - // from chaincode, e.g. asset already exists, and return those as a - // 400 error with message instead. Unfortunately the asset transfer - // sample or Fabric Node SDK do not provide any well defined error - // codes that can be checked. - await clearTransactionDetails(redis, txnId); - logger.error( err, 'Error processing update asset request for asset ID %s with transaction ID %s', req.params.assetId, - txnId + err.transactionId ); + + if (err instanceof AssetNotFoundError) { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -364,45 +332,30 @@ assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { const contract: Contract = req.app.get('contract'); const redis: Redis = req.app.get('redis'); - const txn = contract.createTransaction('DeleteAsset'); - const txnId = txn.getTransactionId(); - const txnState = txn.serialize(); - const txnArgs = JSON.stringify([req.params.assetId]); + const assetId = req.params.assetId; try { - const timestamp = Date.now(); - - // Store the transaction details and set the event handler in case there - // are problems later with commiting the transaction - await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); - txn.setEventHandler(createDeferredEventHandler(redis)); - - await txn.submit(req.params.assetId); + await submitTransaction(contract, redis, 'DeleteAsset', assetId); return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), timestamp: new Date().toISOString(), }); } catch (err) { - // TODO will this always catch endorsement errors or can those - // arrive later? - - // There's no point retrying a transaction if there were business - // logic errors so clear the transaction details - // - // Note: it would be nice to pick out business logic errors returned - // from chaincode, e.g. asset already exists, and return those as a - // 400 error with message instead. Unfortunately the asset transfer - // sample or Fabric Node SDK do not provide any well defined error - // codes that can be checked. - await clearTransactionDetails(redis, txnId); - logger.error( err, 'Error processing delete asset request for asset ID %s with transaction ID %s', - req.params.assetId, - txnId + assetId, + err.transactionId ); + + if (err instanceof AssetNotFoundError) { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.ts b/asset-transfer-basic/rest-api-typescript/src/errors.ts new file mode 100644 index 00000000..beb03478 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/errors.ts @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +export class TransactionError extends Error { + transactionId: string; + + constructor(message: string, transactionId: string) { + super(message); + Object.setPrototypeOf(this, TransactionError.prototype); + + this.name = 'TransactionError'; + this.transactionId = transactionId; + } +} + +export class AssetExistsError extends TransactionError { + constructor(message: string, transactionId: string) { + super(message, transactionId); + Object.setPrototypeOf(this, AssetExistsError.prototype); + + this.name = 'AssetExistsError'; + } +} + +export class AssetNotFoundError extends TransactionError { + constructor(message: string, transactionId: string) { + super(message, transactionId); + Object.setPrototypeOf(this, AssetNotFoundError.prototype); + + this.name = 'AssetNotFoundError'; + } +} diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 495238f3..cb4e551a 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -16,6 +16,12 @@ import { import { Redis } from 'ioredis'; import * as config from './config'; import { logger } from './logger'; +import { storeTransactionDetails, clearTransactionDetails } from './redis'; +import { + AssetExistsError, + AssetNotFoundError, + TransactionError, +} from './errors'; export const getContract = async (): Promise => { const wallet = await Wallets.newInMemoryWallet(); @@ -174,6 +180,86 @@ export const startRetryLoop = (contract: Contract, redis: Redis): void => { ); }; +export const evatuateTransaction = async ( + contract: Contract, + transactionName: string, + ...transactionArgs: string[] +): Promise => { + const txn = contract.createTransaction(transactionName); + const txnId = txn.getTransactionId(); + + try { + return await txn.evaluate(...transactionArgs); + } catch (err) { + throw handleError(txnId, err); + } +}; + +export const submitTransaction = async ( + contract: Contract, + redis: Redis, + transactionName: string, + ...transactionArgs: string[] +): Promise => { + const txn = contract.createTransaction(transactionName); + const txnId = txn.getTransactionId(); + const txnState = txn.serialize(); + const txnArgs = JSON.stringify(transactionArgs); + const timestamp = Date.now(); + + try { + // Store the transaction details and set the event handler in case there + // are problems later with commiting the transaction + await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); + txn.setEventHandler(createDeferredEventHandler(redis)); + + await txn.submit(...transactionArgs); + } catch (err) { + // If the transaction failed to endorse, there is no point attempting + // to retry it later so clear the transaction details + // TODO will this always catch endorsement errors or can they + // arrive later? + await clearTransactionDetails(redis, txnId); + throw handleError(txnId, err); + } + + return txnId; +}; + +// Unfortunately the chaincode samples do not use error codes, and the error +// message text is not the same for each implementation +const handleError = (transactionId: string, err: Error): Error => { + // This regex needs to match the following error messages: + // "the asset %s already exists" + // "The asset ${id} already exists" + // "Asset %s already exists" + const assetAlreadyExistsRegex = /([tT]he )?[aA]sset \w* already exists/g; + const assetAlreadyExistsMatch = err.message.match(assetAlreadyExistsRegex); + logger.debug( + { message: err.message, result: assetAlreadyExistsMatch }, + 'Checking for asset already exists message' + ); + if (assetAlreadyExistsMatch) { + return new AssetExistsError(assetAlreadyExistsMatch[0], transactionId); + } + + // This regex needs to match the following error messages: + // "the asset %s does not exist" + // "The asset ${id} does not exist" + // "Asset %s does not exist" + const assetDoesNotExistRegex = /([tT]he )?[aA]sset \w* does not exist/g; + const assetDoesNotExistMatch = err.message.match(assetDoesNotExistRegex); + logger.debug( + { message: err.message, result: assetDoesNotExistMatch }, + 'Checking for asset does not exist message' + ); + if (assetDoesNotExistMatch) { + return new AssetNotFoundError(assetDoesNotExistMatch[0], transactionId); + } + + return new TransactionError('Transaction error', transactionId); +}; + const retryTransaction = async ( contract: Contract, redis: Redis, @@ -225,58 +311,3 @@ const isDuplicateTransaction = (error: { return false; }; - -// TODO move these to redis.ts? - -export const storeTransactionDetails = async ( - redis: Redis, - transactionId: string, - transactionState: Buffer, - transactionArgs: string, - timestamp: number -): Promise => { - const key = `txn:${transactionId}`; - logger.debug( - 'Storing transaction details. Key: %s State: %s Args: %s Timestamp: %d', - key, - transactionState, - transactionArgs, - timestamp - ); - await redis - .multi() - .hset( - key, - 'state', - transactionState, - 'args', - transactionArgs, - 'timestamp', - timestamp, - 'retries', - '0' - ) - .zadd('index:txn:timestamp', timestamp, transactionId) - .exec(); -}; - -export const clearTransactionDetails = async ( - redis: Redis, - transactionId: string -): Promise => { - const key = `txn:${transactionId}`; - logger.debug('Removing transaction details. Key: %s', key); - try { - await redis - .multi() - .del(key) - .zrem('index:txn:timestamp', transactionId) - .exec(); - } catch (err) { - logger.error( - err, - 'Error remove saved transaction state for transaction ID %s', - transactionId - ); - } -}; diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.ts b/asset-transfer-basic/rest-api-typescript/src/redis.ts index 9cc79dba..d799d800 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.ts @@ -2,9 +2,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import IORedis, { RedisOptions } from 'ioredis'; +import IORedis, { Redis, RedisOptions } from 'ioredis'; import * as config from './config'; +import { logger } from './logger'; const redisOptions: RedisOptions = { port: config.redisPort, @@ -14,3 +15,58 @@ const redisOptions: RedisOptions = { }; export const redis = new IORedis(redisOptions); + +export const storeTransactionDetails = async ( + redis: Redis, + transactionId: string, + transactionState: Buffer, + transactionArgs: string, + timestamp: number +): Promise => { + const key = `txn:${transactionId}`; + logger.debug( + 'Storing transaction details. Key: %s State: %s Args: %s Timestamp: %d', + key, + transactionState, + transactionArgs, + timestamp + ); + await redis + .multi() + .hset( + key, + 'state', + transactionState, + 'args', + transactionArgs, + 'timestamp', + timestamp, + 'retries', + '0' + ) + .zadd('index:txn:timestamp', timestamp, transactionId) + .exec(); +}; + +export const clearTransactionDetails = async ( + redis: Redis, + transactionId: string +): Promise => { + const key = `txn:${transactionId}`; + logger.debug('Removing transaction details. Key: %s', key); + try { + await redis + .multi() + .del(key) + .zrem('index:txn:timestamp', transactionId) + .exec(); + } catch (err) { + logger.error( + err, + 'Error remove saved transaction state for transaction ID %s', + transactionId + ); + } +}; + +// TODO add getTransaction etc. helpers? From 432da5defde6f0c6b2c1c92870aa1ee0859148b4 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 21 Jul 2021 12:17:10 +0100 Subject: [PATCH 056/106] Add get transaction endpoint Signed-off-by: James Taylor --- .../rest-api-typescript/src/assets.router.ts | 31 +++-- .../rest-api-typescript/src/errors.ts | 12 ++ .../rest-api-typescript/src/fabric.ts | 39 ++++++- .../rest-api-typescript/src/server.ts | 9 +- .../src/transactions.router.ts | 108 ++++++++++++++++++ 5 files changed, 181 insertions(+), 18 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/transactions.router.ts diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index f70db1e3..ccf5690a 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -34,7 +34,7 @@ assetsRouter.get('/', async (req: Request, res: Response) => { logger.debug('Get all assets request received'); try { - const contract: Contract = req.app.get('contract'); + const contract: Contract = req.app.get('contracts').contract; const data = await evatuateTransaction(contract, 'GetAllAssets'); const assets = JSON.parse(data.toString()); @@ -71,12 +71,12 @@ assetsRouter.post( }); } - const contract: Contract = req.app.get('contract'); + const contract: Contract = req.app.get('contracts').contract; const redis: Redis = req.app.get('redis'); const assetId = req.body.id; try { - await submitTransaction( + const transactionId = await submitTransaction( contract, redis, 'CreateAsset', @@ -89,6 +89,7 @@ assetsRouter.post( return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), + transactionId: transactionId, timestamp: new Date().toISOString(), }); } catch (err) { @@ -121,7 +122,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { logger.debug('Asset options request received for asset ID %s', assetId); try { - const contract: Contract = req.app.get('contract'); + const contract: Contract = req.app.get('contracts').contract; const data = await evatuateTransaction(contract, 'AssetExists', assetId); const exists = data.toString() === 'true'; @@ -160,7 +161,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { logger.debug('Read asset request received for asset ID %s', assetId); try { - const contract: Contract = req.app.get('contract'); + const contract: Contract = req.app.get('contracts').contract; const data = await evatuateTransaction(contract, 'ReadAsset', assetId); const asset = JSON.parse(data.toString()); @@ -218,12 +219,12 @@ assetsRouter.put( }); } - const contract: Contract = req.app.get('contract'); + const contract: Contract = req.app.get('contracts').contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; try { - await submitTransaction( + const transactionId = await submitTransaction( contract, redis, 'UpdateAsset', @@ -236,6 +237,7 @@ assetsRouter.put( return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), + transactionId: transactionId, timestamp: new Date().toISOString(), }); } catch (err) { @@ -286,13 +288,13 @@ assetsRouter.patch( }); } - const contract: Contract = req.app.get('contract'); + const contract: Contract = req.app.get('contracts').contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; const newOwner = req.body[0].value; try { - await submitTransaction( + const transactionId = await submitTransaction( contract, redis, 'TransferAsset', @@ -302,6 +304,7 @@ assetsRouter.patch( return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), + transactionId: transactionId, timestamp: new Date().toISOString(), }); } catch (err) { @@ -330,15 +333,21 @@ assetsRouter.patch( assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { logger.debug(req.body, 'Delete asset request received'); - const contract: Contract = req.app.get('contract'); + const contract: Contract = req.app.get('contracts').contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; try { - await submitTransaction(contract, redis, 'DeleteAsset', assetId); + const transactionId = await submitTransaction( + contract, + redis, + 'DeleteAsset', + assetId + ); return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), + transactionId: transactionId, timestamp: new Date().toISOString(), }); } catch (err) { diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.ts b/asset-transfer-basic/rest-api-typescript/src/errors.ts index beb03478..21692ac1 100644 --- a/asset-transfer-basic/rest-api-typescript/src/errors.ts +++ b/asset-transfer-basic/rest-api-typescript/src/errors.ts @@ -14,6 +14,18 @@ export class TransactionError extends Error { } } +export class TransactionNotFoundError extends Error { + transactionId: string; + + constructor(message: string, transactionId: string) { + super(message); + Object.setPrototypeOf(this, TransactionNotFoundError.prototype); + + this.name = 'TransactionNotFoundError'; + this.transactionId = transactionId; + } +} + export class AssetExistsError extends TransactionError { constructor(message: string, transactionId: string) { super(message, transactionId); diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index cb4e551a..2419d0e1 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -21,9 +21,10 @@ import { AssetExistsError, AssetNotFoundError, TransactionError, + TransactionNotFoundError, } from './errors'; -export const getContract = async (): Promise => { +export const getGateway = async (): Promise => { const wallet = await Wallets.newInMemoryWallet(); const x509Identity = { @@ -55,10 +56,18 @@ export const getContract = async (): Promise => { await gateway.connect(config.connectionProfile, connectOptions); - const network = await gateway.getNetwork(config.channelName); - const contract = network.getContract(config.chaincodeName); + return gateway; +}; - return contract; +export const getContracts = async ( + gateway: Gateway +): Promise<{ contract: Contract; qscc: Contract }> => { + const network = await gateway.getNetwork(config.channelName); + + const contract = network.getContract(config.chaincodeName); + const qscc = network.getContract('qscc'); + + return { contract, qscc }; }; export const createDeferredEventHandler = ( @@ -257,6 +266,28 @@ const handleError = (transactionId: string, err: Error): Error => { return new AssetNotFoundError(assetDoesNotExistMatch[0], transactionId); } + // This regex needs to match the following error messages: + // "Failed to get transaction with id %s, error Entry not found in index" + const transactionDoesNotExistRegex = + /Failed to get transaction with id [^,]*, error Entry not found in index/g; + const transactionDoesNotExistMatch = err.message.match( + transactionDoesNotExistRegex + ); + logger.debug( + { message: err.message, result: transactionDoesNotExistMatch }, + 'Checking for transaction does not exist message' + ); + if (transactionDoesNotExistMatch) { + return new TransactionNotFoundError( + transactionDoesNotExistMatch[0], + transactionId + ); + } + + logger.error( + { transactionId: transactionId, error: err }, + 'Unhandled transaction error' + ); return new TransactionError('Transaction error', transactionId); }; diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index f22f5fdd..180278c4 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -9,7 +9,8 @@ import pinoMiddleware from 'pino-http'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; -import { getContract } from './fabric'; +import { transactionsRouter } from './transactions.router'; +import { getContracts, getGateway } from './fabric'; import { redis } from './redis'; const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; @@ -48,8 +49,9 @@ export const createServer = async (): Promise => { app.use(helmet()); } - const contract = await getContract(); - app.set('contract', contract); + const gateway = await getGateway(); + const contracts = await getContracts(gateway); + app.set('contracts', contracts); app.set('redis', redis); // Health routes @@ -72,6 +74,7 @@ export const createServer = async (): Promise => { }); app.use('/api/assets', assetsRouter); + app.use('/api/transactions', transactionsRouter); // For everything else app.use((_req, res) => diff --git a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts new file mode 100644 index 00000000..2a0bc987 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts @@ -0,0 +1,108 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import express, { Request, Response } from 'express'; +import { Contract } from 'fabric-network'; +import { protos } from 'fabric-protos'; +import { getReasonPhrase, StatusCodes } from 'http-status-codes'; +import { Redis } from 'ioredis'; +import { evatuateTransaction } from './fabric'; +import { logger } from './logger'; +import * as config from './config'; +import { TransactionNotFoundError } from './errors'; + +const { INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; + +export const transactionsRouter = express.Router(); + +type Progress = 'ACCEPTED' | 'RETRYING' | 'DONE'; + +transactionsRouter.get( + '/:transactionId', + async (req: Request, res: Response) => { + const transactionId = req.params.transactionId; + logger.debug('Read request received for transaction ID %s', transactionId); + + let foundTransaction = false; + let progress: Progress = 'DONE'; + let validationCode = ''; + + const qscc: Contract = req.app.get('contracts').qscc; + const redis: Redis = req.app.get('redis'); + + try { + const savedTransaction = await (redis as Redis).hgetall( + `txn:${transactionId}` + ); + logger.debug( + { transactionId: transactionId, state: savedTransaction }, + 'Saved transaction state' + ); + + if (savedTransaction.state) { + foundTransaction = true; + const retries = parseInt(savedTransaction.retries); + if (retries > 0) { + progress = 'RETRYING'; + } else { + progress = 'ACCEPTED'; + } + } + } catch (err) { + logger.error( + err, + 'Redis error processing read request for transaction ID %s', + transactionId + ); + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + + try { + const data = await evatuateTransaction( + qscc, + 'GetTransactionByID', + config.channelName, + transactionId + ); + + foundTransaction = true; + // TODO is it possible to use the BlockDecoder decodeTransaction + // function in fabric-common? + const processedTransaction = protos.ProcessedTransaction.decode(data); + validationCode = + protos.TxValidationCode[processedTransaction.validationCode]; + } catch (err) { + if (!(err instanceof TransactionNotFoundError)) { + logger.error( + err, + 'Fabric error processing read request for transaction ID %s', + transactionId + ); + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } + + if (foundTransaction) { + return res.status(OK).json({ + status: getReasonPhrase(OK), + progress: progress, + validationCode: validationCode, + timestamp: new Date().toISOString(), + }); + } else { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + } +); From 3667dd93228822b1affd358ad32677714704eb9d Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 22 Jul 2021 12:12:30 +0100 Subject: [PATCH 057/106] Add Jira link to readme Also adds new transactions endpoint example Signed-off-by: James Taylor --- README.md | 28 +++++++++++++++++++--------- demo.http | 4 ++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 24b890b0..aaf539be 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Fabric REST sample -Prototype sample REST server to demonstrate good Fabric Node SDK practices +Prototype sample REST server to demonstrate good Fabric Node SDK practices for parts of [FAB-18511](https://jira.hyperledger.org/browse/FAB-18511) The primary aim of this sample is to show how to write a long running client application using the Fabric Node SDK @@ -8,6 +8,8 @@ The REST API is intended to work with the [basic asset transfer example](https:/ To install the basic asset transfer chaincode on a local Fabric network, follow the [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/release-2.2/test_network.html) tutorial +## Usage + **Note:** these instructions should work with the release-2.2 branch of `fabric-samples` but later versions require some changes To build and start the sample REST server, you'll need to [download and install an LTS version of node](https://nodejs.org/en/download/) @@ -44,45 +46,53 @@ Start the sample REST server npm run start:dev ``` -If everything went well, you can now make REST calls! +## REST API -For example, get all assets... +If everything went well, you can now make basic asset transfer REST calls! For example... + +### Get all assets... ```shell curl http://localhost:3000/api/assets ``` -Check whether an asset exists... +### Check whether an asset exists... ```shell curl --include --request OPTIONS http://localhost:3000/api/assets/asset7 ``` -Create an asset... +### Create an asset... ```shell curl --include --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets ``` -Read an asset... +### Read transaction status... + +```shell +curl http://localhost:3000/api/transactions/__transaction_id__ +``` + +### Read an asset... ```shell curl http://localhost:3000/api/assets/asset7 ``` -Update an asset... +### Update an asset... ```shell curl --include --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 ``` -Transfer an asset... +### Transfer an asset... ```shell curl --include --header "Content-Type: application/json" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 ``` -Delete an asset... +### Delete an asset... ```shell curl --include --request DELETE http://localhost:3000/api/assets/asset7 diff --git a/demo.http b/demo.http index bf5e0961..7873879f 100644 --- a/demo.http +++ b/demo.http @@ -25,6 +25,10 @@ content-type: application/json "appraisedValue": 101 } +### Read transaction status + +GET {{baseUrl}}/transactions/__transaction_id__ HTTP/1.1 + ### Read asset GET {{baseUrl}}/assets/asset7 HTTP/1.1 From 19e28d817be8a26500f89979bbc21041f6446654 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 22 Jul 2021 17:45:59 +0100 Subject: [PATCH 058/106] Fix retry Adding multiple contracts had broken the retry loop Signed-off-by: James Taylor --- asset-transfer-basic/rest-api-typescript/src/fabric.ts | 6 +++++- asset-transfer-basic/rest-api-typescript/src/index.ts | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 2419d0e1..44066d65 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -160,6 +160,10 @@ export const startRetryLoop = (contract: Contract, redis: Redis): void => { pendingTransactionCount ); + // TODO pick a random transaction instead to reduce chances of + // clashing with other instances? Currently no zrandmember + // command though... + // https://github.com/luin/ioredis/issues/1374 const transactionIds = await (redis as Redis).zrange( 'index:txn:timestamp', -1, @@ -309,7 +313,7 @@ const retryTransaction = async ( await clearTransactionDetails(redis, transactionId); } catch (err) { if (isDuplicateTransaction(err)) { - logger.debug('Transaction %s has already been committed', transactionId); + logger.warn('Transaction %s has already been committed', transactionId); await clearTransactionDetails(redis, transactionId); } else { // TODO check for retry limit and update timestamp diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index b91a6c3f..12e167c0 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -12,7 +12,7 @@ import { createServer } from './server'; async function main() { const app = await createServer(); - const contract: Contract = app.get('contract'); + const contract: Contract = app.get('contracts').contract; const redis: Redis = app.get('redis'); startRetryLoop(contract, redis); From 804f4a6468010a2b2e2bf5308499efe34ce9784f Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Mon, 26 Jul 2021 11:59:41 +0530 Subject: [PATCH 059/106] added getNetwork functionality Signed-off-by: sapthasurendran --- asset-transfer-basic/rest-api-typescript/src/fabric.ts | 8 ++++++++ asset-transfer-basic/rest-api-typescript/src/server.ts | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 44066d65..da6cc722 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -12,6 +12,7 @@ import { TxEventHandler, TxEventHandlerFactory, Wallets, + Network } from 'fabric-network'; import { Redis } from 'ioredis'; import * as config from './config'; @@ -24,6 +25,12 @@ import { TransactionNotFoundError, } from './errors'; + +export const getNetwork = async (gateway: Gateway): Promise => { + const network = await gateway.getNetwork(config.channelName); + return network; +}; + export const getGateway = async (): Promise => { const wallet = await Wallets.newInMemoryWallet(); @@ -346,3 +353,4 @@ const isDuplicateTransaction = (error: { return false; }; + diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 180278c4..5d5f4269 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -10,7 +10,7 @@ import pinoMiddleware from 'pino-http'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; import { transactionsRouter } from './transactions.router'; -import { getContracts, getGateway } from './fabric'; +import { getContracts, getGateway, getNetwork } from './fabric'; import { redis } from './redis'; const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; @@ -51,8 +51,10 @@ export const createServer = async (): Promise => { const gateway = await getGateway(); const contracts = await getContracts(gateway); + const network = await getNetwork(gateway) app.set('contracts', contracts); app.set('redis', redis); + app.set('network',network) // Health routes app.get('/ready', (_req, res) => From 550e95f09158bfdece3536803569ae1d3eb6f8e5 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Mon, 26 Jul 2021 12:38:52 +0530 Subject: [PATCH 060/106] Added blockEvent handler Signed-off-by: sapthasurendran --- .../rest-api-typescript/src/fabric.ts | 24 +++++++++++++++++-- .../rest-api-typescript/src/index.ts | 6 +++-- .../rest-api-typescript/src/server.ts | 4 ++-- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index da6cc722..a2e08a8d 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -12,7 +12,10 @@ import { TxEventHandler, TxEventHandlerFactory, Wallets, - Network + Network, + BlockListener, + BlockEvent, + TransactionEvent, } from 'fabric-network'; import { Redis } from 'ioredis'; import * as config from './config'; @@ -25,7 +28,6 @@ import { TransactionNotFoundError, } from './errors'; - export const getNetwork = async (gateway: Gateway): Promise => { const network = await gateway.getNetwork(config.channelName); return network; @@ -354,3 +356,21 @@ const isDuplicateTransaction = (error: { return false; }; +export const blockEventHandler = (redis: Redis): BlockListener => { + const blockListner = async (event: BlockEvent) => { + logger.debug('Block event received '); + const transEvents: Array = event.getTransactionEvents(); + + for (const transEvent of transEvents) { + if (transEvent && transEvent.isValid) { + logger.debug( + 'Remove transation with txnId %s', + transEvent.transactionId + ); + await clearTransactionDetails(redis, transEvent.transactionId); + } + } + }; + + return blockListner; +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 12e167c0..9d65028e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -2,10 +2,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Contract } from 'fabric-network'; +import { Contract, Network } from 'fabric-network'; import { Redis } from 'ioredis'; import * as config from './config'; -import { startRetryLoop } from './fabric'; +import { startRetryLoop, blockEventHandler } from './fabric'; import { logger } from './logger'; import { createServer } from './server'; @@ -14,6 +14,8 @@ async function main() { const contract: Contract = app.get('contracts').contract; const redis: Redis = app.get('redis'); + const network: Network = app.get('network'); + await network.addBlockListener(blockEventHandler(redis)); startRetryLoop(contract, redis); app.listen(config.port, () => { diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 5d5f4269..e3ed3fb6 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -51,10 +51,10 @@ export const createServer = async (): Promise => { const gateway = await getGateway(); const contracts = await getContracts(gateway); - const network = await getNetwork(gateway) + const network = await getNetwork(gateway); app.set('contracts', contracts); app.set('redis', redis); - app.set('network',network) + app.set('network', network); // Health routes app.get('/ready', (_req, res) => From 5d6e916436fa3e1b290f6b8bda7330ae87f981a3 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Mon, 26 Jul 2021 14:53:53 +0530 Subject: [PATCH 061/106] changed getContract arg Signed-off-by: sapthasurendran --- asset-transfer-basic/rest-api-typescript/src/fabric.ts | 5 +---- asset-transfer-basic/rest-api-typescript/src/server.ts | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index a2e08a8d..af831efe 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -69,13 +69,10 @@ export const getGateway = async (): Promise => { }; export const getContracts = async ( - gateway: Gateway + network: Network ): Promise<{ contract: Contract; qscc: Contract }> => { - const network = await gateway.getNetwork(config.channelName); - const contract = network.getContract(config.chaincodeName); const qscc = network.getContract('qscc'); - return { contract, qscc }; }; diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index e3ed3fb6..e2586cba 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -50,8 +50,8 @@ export const createServer = async (): Promise => { } const gateway = await getGateway(); - const contracts = await getContracts(gateway); const network = await getNetwork(gateway); + const contracts = await getContracts(network); app.set('contracts', contracts); app.set('redis', redis); app.set('network', network); From 31b08b91515306362e87ef3534b703bc2786a296 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Mon, 26 Jul 2021 15:02:06 +0530 Subject: [PATCH 062/106] removed txn commit event handler Signed-off-by: sapthasurendran --- .../rest-api-typescript/src/fabric.ts | 84 +------------------ 1 file changed, 1 insertion(+), 83 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index af831efe..25bead39 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -3,14 +3,11 @@ */ import { - CommitListener, Contract, DefaultEventHandlerStrategies, DefaultQueryHandlerStrategies, Gateway, GatewayOptions, - TxEventHandler, - TxEventHandlerFactory, Wallets, Network, BlockListener, @@ -55,7 +52,7 @@ export const getGateway = async (): Promise => { eventHandlerOptions: { commitTimeout: config.commitTimeout, endorseTimeout: config.endorseTimeout, - strategy: DefaultEventHandlerStrategies.PREFER_MSPID_SCOPE_ANYFORTX, + strategy: DefaultEventHandlerStrategies.NONE, }, queryHandlerOptions: { timeout: 3, @@ -76,84 +73,6 @@ export const getContracts = async ( return { contract, qscc }; }; -export const createDeferredEventHandler = ( - redis: Redis -): TxEventHandlerFactory => { - return (transactionId, network): TxEventHandler => { - // TODO would like to store the transaction details here - // but doesn't seem possible to use await or handle errors - // in the TxEventHandlerFactory :( - - const mspId = network.getGateway().getIdentity().mspId; - const peers = network.getChannel().getEndorsers(mspId); - - const options = Object.assign( - { - commitTimeout: 30, - }, - network.getGateway().getOptions().eventHandlerOptions - ); - - const removeCommitListener = async () => { - network.removeCommitListener(listener); - logger.debug( - 'Stopped listening for transaction %s events', - transactionId - ); - - const txnExists = await redis.exists(transactionId); - if (txnExists) { - logger.warn( - 'Transaction %s was not successfully committed', - transactionId - ); - } - }; - - const listener: CommitListener = async (error, event) => { - if (error) { - logger.error(error, 'Commit error for transaction %s', transactionId); - } - - if (event && event.isValid) { - logger.debug('Transaction %s successfully committed', transactionId); - - await clearTransactionDetails(redis, transactionId); - await removeCommitListener(); - } - }; - - const deferredEventHandler: TxEventHandler = { - startListening: async () => { - logger.debug('Setting timeout for %d ms', options.commitTimeout * 1000); - setTimeout(async () => { - logger.debug( - 'Timeout listening for transaction %s events', - transactionId - ); - await removeCommitListener(); - }, options.commitTimeout * 1000); - - await network.addCommitListener(listener, peers, transactionId); - logger.debug('Listening for transaction %s events', transactionId); - }, - waitForEvents: async () => { - // No-op - }, - cancelListening: async () => { - // TODO this is what the doc says, but is it true?! - logger.warn( - 'Submission of transaction %s to the orderer failed', - transactionId - ); - await removeCommitListener(); - }, - }; - - return deferredEventHandler; - }; -}; - export const startRetryLoop = (contract: Contract, redis: Redis): void => { setInterval( async (redis) => { @@ -230,7 +149,6 @@ export const submitTransaction = async ( // Store the transaction details and set the event handler in case there // are problems later with commiting the transaction await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); - txn.setEventHandler(createDeferredEventHandler(redis)); await txn.submit(...transactionArgs); } catch (err) { From fc769cfcb0b7808de1d83b996dce6260c34eb40f Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Mon, 26 Jul 2021 15:19:26 +0530 Subject: [PATCH 063/106] event handler strategy changes Signed-off-by: sapthasurendran --- asset-transfer-basic/rest-api-typescript/src/fabric.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 25bead39..ab099842 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -52,7 +52,7 @@ export const getGateway = async (): Promise => { eventHandlerOptions: { commitTimeout: config.commitTimeout, endorseTimeout: config.endorseTimeout, - strategy: DefaultEventHandlerStrategies.NONE, + strategy: DefaultEventHandlerStrategies.PREFER_MSPID_SCOPE_ANYFORTX, }, queryHandlerOptions: { timeout: 3, @@ -149,7 +149,7 @@ export const submitTransaction = async ( // Store the transaction details and set the event handler in case there // are problems later with commiting the transaction await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); - + txn.setEventHandler(DefaultEventHandlerStrategies.NONE); await txn.submit(...transactionArgs); } catch (err) { // If the transaction failed to endorse, there is no point attempting From d4318c381adcc5ec7eb435ad37a6a00e2837a001 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Fri, 23 Jul 2021 16:15:27 +0530 Subject: [PATCH 064/106] liveness used fabric protos insted of blockdecoder changed import statement Signed-off-by: sapthasurendran revert back eslintrc Signed-off-by: sapthasurendran function name change Signed-off-by: sapthasurendran format changes Signed-off-by: sapthasurendran --- .../rest-api-typescript/src/fabric.ts | 17 ++++++++++ .../rest-api-typescript/src/server.ts | 31 ++++++++++++++----- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index ab099842..d96abe9b 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -24,6 +24,7 @@ import { TransactionError, TransactionNotFoundError, } from './errors'; +import fabproto6 from 'fabric-protos'; export const getNetwork = async (gateway: Gateway): Promise => { const network = await gateway.getNetwork(config.channelName); @@ -289,3 +290,19 @@ export const blockEventHandler = (redis: Redis): BlockListener => { return blockListner; }; + +export const getChainInfo = async (qscc: Contract): Promise => { + try { + const data = await qscc.evaluateTransaction( + 'GetChainInfo', + config.channelName + ); + const info = fabproto6.common.BlockchainInfo.decode(data); + const blockHeight = info.height.toString(); + logger.info('Current block height: %s', blockHeight); + return true; + } catch (e) { + logger.error(e, 'Unable to get blockchain info'); + return false; + } +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index e2586cba..c0b51a38 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -10,10 +10,17 @@ import pinoMiddleware from 'pino-http'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; import { transactionsRouter } from './transactions.router'; -import { getContracts, getGateway, getNetwork } from './fabric'; +import { getContracts, getGateway, getNetwork, getChainInfo } from './fabric'; import { redis } from './redis'; +import { Contract } from 'fabric-network'; -const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; +const { + BAD_REQUEST, + INTERNAL_SERVER_ERROR, + NOT_FOUND, + OK, + SERVICE_UNAVAILABLE, +} = StatusCodes; export const createServer = async (): Promise => { const app = express(); @@ -63,12 +70,20 @@ export const createServer = async (): Promise => { timestamp: new Date().toISOString(), }) ); - app.get('/live', (_req, res) => - res.status(OK).json({ - status: getReasonPhrase(OK), - timestamp: new Date().toISOString(), - }) - ); + app.get('/live', async (_req, res) => { + const qscc: Contract = _req.app.get('contracts').qscc; + if ((await getChainInfo(qscc)) === true) { + res.status(OK).json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }); + } else { + res.status(SERVICE_UNAVAILABLE).json({ + status: getReasonPhrase(SERVICE_UNAVAILABLE), + timestamp: new Date().toISOString(), + }); + } + }); // TODO delete me app.get('/error', (_req, _res) => { From c3a34ef5593ba82fe006fe12c327332c9be64841 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Tue, 27 Jul 2021 13:13:18 +0530 Subject: [PATCH 065/106] apikey auth for Org1 Signed-off-by: sapthasurendran removed auth check from live,ready apis.. code format http file changes for apikey comments for getting api key readme update for apikey usage replaced -H with --header apikey config made mandatory fix linting Signed-off-by: sapthasurendran --- README.md | 12 +++--- .../rest-api-typescript/package-lock.json | 37 +++++++++++++++++++ .../rest-api-typescript/package.json | 3 ++ .../scripts/generateEnv.sh | 2 + .../rest-api-typescript/src/auth.ts | 24 ++++++++++++ .../rest-api-typescript/src/config.ts | 6 +++ .../rest-api-typescript/src/server.ts | 20 +++++++++- demo.http | 12 +++++- 8 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/auth.ts diff --git a/README.md b/README.md index aaf539be..33e8175e 100644 --- a/README.md +++ b/README.md @@ -65,35 +65,35 @@ curl --include --request OPTIONS http://localhost:3000/api/assets/asset7 ### Create an asset... ```shell -curl --include --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets +curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets ``` ### Read transaction status... ```shell -curl http://localhost:3000/api/transactions/__transaction_id__ +curl --header "api-key:Api-Key " http://localhost:3000/api/transactions/__transaction_id__ ``` ### Read an asset... ```shell -curl http://localhost:3000/api/assets/asset7 +curl --header "api-key:Api-Key " http://localhost:3000/api/assets/asset7 ``` ### Update an asset... ```shell -curl --include --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 +curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 ``` ### Transfer an asset... ```shell -curl --include --header "Content-Type: application/json" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 +curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 ``` ### Delete an asset... ```shell -curl --include --request DELETE http://localhost:3000/api/assets/asset7 +curl --include --header "api-key:Api-Key " --request DELETE http://localhost:3000/api/assets/asset7 ``` diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index 4c4d1114..4e25209a 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -268,6 +268,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz", "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==" }, + "@types/passport": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.7.tgz", + "integrity": "sha512-JtswU8N3kxBYgo+n9of7C97YQBT+AYPP2aBfNGTzABqPAZnK/WOAaKfh3XesUYMZRrXFuoPc2Hv0/G/nQFveHw==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/pino": { "version": "6.3.8", "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.8.tgz", @@ -1961,6 +1970,29 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-headerapikey": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/passport-headerapikey/-/passport-headerapikey-1.2.2.tgz", + "integrity": "sha512-4BvVJRrWsNJPrd3UoZfcnnl4zvUWYKEtfYkoDsaOKBsrWHYmzTApCjs7qUbncOLexE9ul0IRiYBFfBG0y9IVQA==", + "requires": { + "lodash": "^4.17.15", + "passport-strategy": "^1.0.0" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1984,6 +2016,11 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index cfee92bd..1b1aa0e6 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -12,6 +12,8 @@ "helmet": "^4.6.0", "http-status-codes": "^2.1.4", "ioredis": "^4.27.6", + "passport": "^0.4.1", + "passport-headerapikey": "^1.2.2", "pino": "^6.11.3", "pino-http": "^5.5.0", "source-map-support": "^0.5.19" @@ -20,6 +22,7 @@ "@types/express": "^4.17.12", "@types/ioredis": "^4.26.4", "@types/node": "^15.12.4", + "@types/passport": "^1.0.7", "@types/pino": "^6.3.8", "@types/pino-http": "^5.4.1", "@typescript-eslint/eslint-plugin": "^4.28.0", diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index fa30cbdc..3d2b7030 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -30,6 +30,8 @@ REDIS_HOST=localhost REDIS_PORT=6379 +ORG1_APIKEY=$(uuidgen) + #REDIS_USERNAME= #REDIS_PASSWORD= diff --git a/asset-transfer-basic/rest-api-typescript/src/auth.ts b/asset-transfer-basic/rest-api-typescript/src/auth.ts new file mode 100644 index 00000000..dcd3e724 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/auth.ts @@ -0,0 +1,24 @@ +import { logger } from './logger'; +import { HeaderAPIKeyStrategy } from 'passport-headerapikey'; +import * as config from './config'; +export const fabricAPIKeyStrategy: HeaderAPIKeyStrategy = + new HeaderAPIKeyStrategy( + { header: 'api-key', prefix: 'Api-Key ' }, + true, + function (apikey, done) { + const user: { org: string } = { + org: '', + }; + if (apikey === config.org1ApiKey) { + user.org = 'Org1'; + logger.info('Organisation set to Org1'); + done(null, user); + + //todo + //add org2 apikey check + } else { + logger.debug('APIKEY Mismatch'); + return done(null, false); + } + } + ); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index cf967dcf..08c33865 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -97,3 +97,9 @@ export const redisUsername = env .asString(); export const redisPassword = env.get('REDIS_PASSWORD').asString(); + +export const org1ApiKey = env + .get('ORG1_APIKEY') + .required() + .example('123') + .asString(); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index c0b51a38..a57dfcda 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -22,6 +22,8 @@ const { SERVICE_UNAVAILABLE, } = StatusCodes; +import { fabricAPIKeyStrategy } from './auth'; +import passport from 'passport'; export const createServer = async (): Promise => { const app = express(); @@ -48,6 +50,12 @@ export const createServer = async (): Promise => { app.use(express.json()); app.use(express.urlencoded({ extended: true })); + //define passport startegy + passport.use(fabricAPIKeyStrategy); + + //initialize passport js + app.use(passport.initialize()); + if (process.env.NODE_ENV === 'development') { // TBC } @@ -90,8 +98,16 @@ export const createServer = async (): Promise => { throw new Error('Example error'); }); - app.use('/api/assets', assetsRouter); - app.use('/api/transactions', transactionsRouter); + app.use( + '/api/assets', + passport.authenticate('headerapikey', { session: false }), + assetsRouter + ); + app.use( + '/api/transactions', + passport.authenticate('headerapikey', { session: false }), + transactionsRouter + ); // For everything else app.use((_req, res) => diff --git a/demo.http b/demo.http index 7873879f..b682c53e 100644 --- a/demo.http +++ b/demo.http @@ -4,18 +4,23 @@ @port = 3000 @baseUrl = http://{{hostname}}:{{port}}/api -### Get all assets +//Get the apikey from .env file +@api-key= Api-Key 295069C9-ABF5-4D2A-A020-2FF9F4E8DF07 +### Get all assets GET {{baseUrl}}/assets HTTP/1.1 +api-key: {{api-key}} ### Check if asset exists OPTIONS {{baseUrl}}/assets/asset7 HTTP/1.1 +api-key: {{api-key}} ### Create asset POST {{baseUrl}}/assets HTTP/1.1 content-type: application/json +api-key: {{api-key}} { "id": "asset7", @@ -28,15 +33,18 @@ content-type: application/json ### Read transaction status GET {{baseUrl}}/transactions/__transaction_id__ HTTP/1.1 +api-key: {{api-key}} ### Read asset GET {{baseUrl}}/assets/asset7 HTTP/1.1 +api-key: {{api-key}} ### Update asset PUT {{baseUrl}}/assets/asset7 HTTP/1.1 content-type: application/json +api-key: {{api-key}} { "id": "asset7", @@ -50,6 +58,7 @@ content-type: application/json PATCH {{baseUrl}}/assets/asset7 HTTP/1.1 content-type: application/json +api-key: {{api-key}} [ { @@ -62,3 +71,4 @@ content-type: application/json ### Delete asset DELETE {{baseUrl}}/assets/asset7 HTTP/1.1 +api-key: {{api-key}} From 05f7026e581826b7716cb343fdfcbf3c5d4a2558 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 27 Jul 2021 15:35:40 +0100 Subject: [PATCH 066/106] Update api key header Use more common X-Api-Key header with no prefix Also updates Unauthorized response to include a json error body and simplifies working with new API key via curl and the vscode rest client Signed-off-by: James Taylor --- README.md | 26 ++++-- .../rest-api-typescript/demo.http | 84 +++++++++++++++++++ .../rest-api-typescript/src/auth.ts | 45 +++++++++- .../rest-api-typescript/src/server.ts | 14 +--- demo.http | 74 ---------------- 5 files changed, 145 insertions(+), 98 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/demo.http delete mode 100644 demo.http diff --git a/README.md b/README.md index 33e8175e..f8ba15c9 100644 --- a/README.md +++ b/README.md @@ -48,52 +48,60 @@ npm run start:dev ## REST API -If everything went well, you can now make basic asset transfer REST calls! For example... +If everything went well, you can now make basic asset transfer REST calls! + +The examples below require a `SAMPLE_APIKEY` environment variable which must be set to an API key from the `.env` file created above. + +For example, to use the ORG1_APIKEY... + +``` +SAMPLE_APIKEY=$(grep ORG1_APIKEY .env | cut -d '=' -f 2-) +``` ### Get all assets... ```shell -curl http://localhost:3000/api/assets +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets ``` ### Check whether an asset exists... ```shell -curl --include --request OPTIONS http://localhost:3000/api/assets/asset7 +curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request OPTIONS http://localhost:3000/api/assets/asset7 ``` ### Create an asset... ```shell -curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets ``` ### Read transaction status... ```shell -curl --header "api-key:Api-Key " http://localhost:3000/api/transactions/__transaction_id__ +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/transactions/__transaction_id__ ``` ### Read an asset... ```shell -curl --header "api-key:Api-Key " http://localhost:3000/api/assets/asset7 +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets/asset7 ``` ### Update an asset... ```shell -curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 ``` ### Transfer an asset... ```shell -curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 ``` ### Delete an asset... ```shell -curl --include --header "api-key:Api-Key " --request DELETE http://localhost:3000/api/assets/asset7 +curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request DELETE http://localhost:3000/api/assets/asset7 ``` diff --git a/asset-transfer-basic/rest-api-typescript/demo.http b/asset-transfer-basic/rest-api-typescript/demo.http new file mode 100644 index 00000000..163c7632 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/demo.http @@ -0,0 +1,84 @@ +// Demo file for use with REST Client for Visual Studio Code +// See https://github.com/Huachao/vscode-restclient +// +// Edit the values below to match your environment if required +@hostname = localhost +@port = {{$dotenv PORT}} +@baseUrl = http://{{hostname}}:{{port}} +@apiUrl = {{baseUrl}}/api +@api-key = {{$dotenv ORG1_APIKEY}} + +### Check the server is ready + +GET {{baseUrl}}/ready HTTP/1.1 + +### Check the server is still live + +GET {{baseUrl}}/live HTTP/1.1 + +### Get all assets + +GET {{apiUrl}}/assets HTTP/1.1 +X-Api-Key: {{api-key}} + +### Check if asset exists + +OPTIONS {{apiUrl}}/assets/asset7 HTTP/1.1 +X-Api-Key: {{api-key}} + +### Create asset + +POST {{apiUrl}}/assets HTTP/1.1 +content-type: application/json +X-Api-Key: {{api-key}} + +{ + "id": "asset7", + "color": "red", + "size": 42, + "owner": "Jean", + "appraisedValue": 101 +} + +### Read transaction status + +GET {{apiUrl}}/transactions/__transaction_id__ HTTP/1.1 +X-Api-Key: {{api-key}} + +### Read asset + +GET {{apiUrl}}/assets/asset7 HTTP/1.1 +X-Api-Key: {{api-key}} + +### Update asset + +PUT {{apiUrl}}/assets/asset7 HTTP/1.1 +content-type: application/json +X-Api-Key: {{api-key}} + +{ + "id": "asset7", + "color": "red", + "size": 11, + "owner": "Jean", + "appraisedValue": 101 +} + +### Transfer asset + +PATCH {{apiUrl}}/assets/asset7 HTTP/1.1 +content-type: application/json +X-Api-Key: {{api-key}} + +[ + { + "op": "replace", + "path": "/owner", + "value": "Ashleigh" + } +] + +### Delete asset + +DELETE {{apiUrl}}/assets/asset7 HTTP/1.1 +X-Api-Key: {{api-key}} diff --git a/asset-transfer-basic/rest-api-typescript/src/auth.ts b/asset-transfer-basic/rest-api-typescript/src/auth.ts index dcd3e724..fe56dd0e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/auth.ts +++ b/asset-transfer-basic/rest-api-typescript/src/auth.ts @@ -1,24 +1,61 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + import { logger } from './logger'; +import passport from 'passport'; +import { NextFunction, Request, Response } from 'express'; import { HeaderAPIKeyStrategy } from 'passport-headerapikey'; +import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import * as config from './config'; + +const { UNAUTHORIZED } = StatusCodes; + export const fabricAPIKeyStrategy: HeaderAPIKeyStrategy = new HeaderAPIKeyStrategy( - { header: 'api-key', prefix: 'Api-Key ' }, - true, + { header: 'X-API-Key', prefix: '' }, + false, function (apikey, done) { + logger.debug({ apikey }, 'Checking X-API-Key'); const user: { org: string } = { org: '', }; if (apikey === config.org1ApiKey) { user.org = 'Org1'; - logger.info('Organisation set to Org1'); + logger.debug('Organisation set to Org1'); done(null, user); //todo //add org2 apikey check } else { - logger.debug('APIKEY Mismatch'); + logger.debug({ apikey }, 'No valid X-API-Key'); return done(null, false); } } ); + +export const authenticateApiKey = ( + req: Request, + res: Response, + next: NextFunction +): void => { + passport.authenticate( + 'headerapikey', + { session: false }, + function (err, user, _info) { + if (err) return next(err); + if (!user) + return res.status(UNAUTHORIZED).json({ + status: getReasonPhrase(UNAUTHORIZED), + reason: 'NO_VALID_APIKEY', + timestamp: new Date().toISOString(), + }); + req.logIn(user, { session: false }, (err) => { + if (err) { + return next(err); + } + return next(); + }); + } + )(req, res, next); +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index a57dfcda..1b900248 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -22,7 +22,7 @@ const { SERVICE_UNAVAILABLE, } = StatusCodes; -import { fabricAPIKeyStrategy } from './auth'; +import { authenticateApiKey, fabricAPIKeyStrategy } from './auth'; import passport from 'passport'; export const createServer = async (): Promise => { const app = express(); @@ -98,16 +98,8 @@ export const createServer = async (): Promise => { throw new Error('Example error'); }); - app.use( - '/api/assets', - passport.authenticate('headerapikey', { session: false }), - assetsRouter - ); - app.use( - '/api/transactions', - passport.authenticate('headerapikey', { session: false }), - transactionsRouter - ); + app.use('/api/assets', authenticateApiKey, assetsRouter); + app.use('/api/transactions', authenticateApiKey, transactionsRouter); // For everything else app.use((_req, res) => diff --git a/demo.http b/demo.http deleted file mode 100644 index b682c53e..00000000 --- a/demo.http +++ /dev/null @@ -1,74 +0,0 @@ -// Demo file for use with REST Client for Visual Studio Code -// See https://github.com/Huachao/vscode-restclient -@hostname = localhost -@port = 3000 -@baseUrl = http://{{hostname}}:{{port}}/api - -//Get the apikey from .env file -@api-key= Api-Key 295069C9-ABF5-4D2A-A020-2FF9F4E8DF07 - -### Get all assets -GET {{baseUrl}}/assets HTTP/1.1 -api-key: {{api-key}} - -### Check if asset exists - -OPTIONS {{baseUrl}}/assets/asset7 HTTP/1.1 -api-key: {{api-key}} - -### Create asset - -POST {{baseUrl}}/assets HTTP/1.1 -content-type: application/json -api-key: {{api-key}} - -{ - "id": "asset7", - "color": "red", - "size": 42, - "owner": "Jean", - "appraisedValue": 101 -} - -### Read transaction status - -GET {{baseUrl}}/transactions/__transaction_id__ HTTP/1.1 -api-key: {{api-key}} - -### Read asset - -GET {{baseUrl}}/assets/asset7 HTTP/1.1 -api-key: {{api-key}} - -### Update asset - -PUT {{baseUrl}}/assets/asset7 HTTP/1.1 -content-type: application/json -api-key: {{api-key}} - -{ - "id": "asset7", - "color": "red", - "size": 11, - "owner": "Jean", - "appraisedValue": 101 -} - -### Transfer asset - -PATCH {{baseUrl}}/assets/asset7 HTTP/1.1 -content-type: application/json -api-key: {{api-key}} - -[ - { - "op": "replace", - "path": "/owner", - "value": "Ashleigh" - } -] - -### Delete asset - -DELETE {{baseUrl}}/assets/asset7 HTTP/1.1 -api-key: {{api-key}} From 9ae66c76da03fb266111617fa33351a8c2e1b0ab Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Wed, 28 Jul 2021 17:33:45 +0530 Subject: [PATCH 067/106] switch gateway based on user org Signed-off-by: sapthasurendran initialized fabric components to global app const getcontractforOrg for transaction router removed org and reused identityOrg1 env.sample file update liveness api update Signed-off-by: sapthasurendran --- .../rest-api-typescript/.env.sample | 17 ++++- .../scripts/generateEnv.sh | 25 +++++-- .../rest-api-typescript/src/assets.router.ts | 21 +++--- .../rest-api-typescript/src/auth.ts | 15 +++-- .../rest-api-typescript/src/config.ts | 67 ++++++++++++++++--- .../rest-api-typescript/src/fabric.ts | 38 ++++++++--- .../rest-api-typescript/src/index.ts | 6 +- .../rest-api-typescript/src/server.ts | 51 +++++++++++--- .../src/transactions.router.ts | 4 +- 9 files changed, 190 insertions(+), 54 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/.env.sample b/asset-transfer-basic/rest-api-typescript/.env.sample index 9fe7cf46..f81d0dcf 100644 --- a/asset-transfer-basic/rest-api-typescript/.env.sample +++ b/asset-transfer-basic/rest-api-typescript/.env.sample @@ -4,11 +4,18 @@ PORT=3000 RETRY_DELAY=3000 -HLF_CONNECTION_PROFILE={"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... } +HLF_CONNECTION_PROFILE_ORG1={"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... } -HLF_CERTIFICATE="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" +HLF_CERTIFICATE_ORG1="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" + +HLF_PRIVATE_KEY_ORG1="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" + +HLF_CONNECTION_PROFILE_ORG2={"name":"test-network-org2","version":"1.0.0","client":{"organization":"Org2" ... } + +HLF_CERTIFICATE_ORG2="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" + +HLF_PRIVATE_KEY_ORG2="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" -HLF_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" HLF_COMMIT_TIMEOUT=3000 @@ -18,6 +25,10 @@ REDIS_HOST=localhost REDIS_PORT=6379 +ORG1_APIKEY=D2F66BFF-D68B-458D-8FA6-285F172D5B03 + +ORG2_APIKEY=92042C1F-8E58-48F9-9EAF-91A98A2B7648 + #REDIS_USERNAME= #REDIS_PASSWORD= diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index 3d2b7030..c0af2374 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -5,9 +5,14 @@ # : "${TEST_NETWORK_HOME:=../..}" -: "${CONNECTION_PROFILE_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" -: "${CERTIFICATE_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem}" -: "${PRIVATE_KEY_FILE:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk}" +: "${CONNECTION_PROFILE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" +: "${CERTIFICATE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem}" +: "${PRIVATE_KEY_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk}" + +: "${CONNECTION_PROFILE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/connection-org2.json}" +: "${CERTIFICATE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem}" +: "${PRIVATE_KEY_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/priv_sk}" + cat << ENV_END > .env LOG_LEVEL=info @@ -16,11 +21,17 @@ PORT=3000 RETRY_DELAY=3000 -HLF_CONNECTION_PROFILE=$(cat ${CONNECTION_PROFILE_FILE} | jq -c .) +HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .) -HLF_CERTIFICATE="$(cat ${CERTIFICATE_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" +HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" -HLF_PRIVATE_KEY="$(cat ${PRIVATE_KEY_FILE} | sed -e 's/$/\\n/' | tr -d '\r\n')" +HLF_PRIVATE_KEY_ORG1="$(cat ${PRIVATE_KEY_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" + +HLF_CONNECTION_PROFILE_ORG2=$(cat ${CONNECTION_PROFILE_FILE_ORG2} | jq -c .) + +HLF_CERTIFICATE_ORG2="$(cat ${CERTIFICATE_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" + +HLF_PRIVATE_KEY_ORG2="$(cat ${PRIVATE_KEY_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" HLF_COMMIT_TIMEOUT=3000 @@ -32,6 +43,8 @@ REDIS_PORT=6379 ORG1_APIKEY=$(uuidgen) +ORG2_APIKEY=$(uuidgen) + #REDIS_USERNAME= #REDIS_PASSWORD= diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index ccf5690a..b1d89a71 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -16,7 +16,11 @@ import { Contract } from 'fabric-network'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { Redis } from 'ioredis'; import { AssetExistsError, AssetNotFoundError } from './errors'; -import { evatuateTransaction, submitTransaction } from './fabric'; +import { + evatuateTransaction, + submitTransaction, + getContractForOrg, +} from './fabric'; import { logger } from './logger'; const { @@ -34,8 +38,7 @@ assetsRouter.get('/', async (req: Request, res: Response) => { logger.debug('Get all assets request received'); try { - const contract: Contract = req.app.get('contracts').contract; - + const contract: Contract = getContractForOrg(req).contract; const data = await evatuateTransaction(contract, 'GetAllAssets'); const assets = JSON.parse(data.toString()); @@ -71,7 +74,7 @@ assetsRouter.post( }); } - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const redis: Redis = req.app.get('redis'); const assetId = req.body.id; @@ -122,7 +125,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { logger.debug('Asset options request received for asset ID %s', assetId); try { - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const data = await evatuateTransaction(contract, 'AssetExists', assetId); const exists = data.toString() === 'true'; @@ -161,7 +164,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { logger.debug('Read asset request received for asset ID %s', assetId); try { - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const data = await evatuateTransaction(contract, 'ReadAsset', assetId); const asset = JSON.parse(data.toString()); @@ -219,7 +222,7 @@ assetsRouter.put( }); } - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; @@ -288,7 +291,7 @@ assetsRouter.patch( }); } - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; const newOwner = req.body[0].value; @@ -333,7 +336,7 @@ assetsRouter.patch( assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { logger.debug(req.body, 'Delete asset request received'); - const contract: Contract = req.app.get('contracts').contract; + const contract: Contract = getContractForOrg(req).contract; const redis: Redis = req.app.get('redis'); const assetId = req.params.assetId; diff --git a/asset-transfer-basic/rest-api-typescript/src/auth.ts b/asset-transfer-basic/rest-api-typescript/src/auth.ts index fe56dd0e..fd40ed43 100644 --- a/asset-transfer-basic/rest-api-typescript/src/auth.ts +++ b/asset-transfer-basic/rest-api-typescript/src/auth.ts @@ -21,12 +21,13 @@ export const fabricAPIKeyStrategy: HeaderAPIKeyStrategy = org: '', }; if (apikey === config.org1ApiKey) { - user.org = 'Org1'; + user.org = config.identityNameOrg1; logger.debug('Organisation set to Org1'); done(null, user); - - //todo - //add org2 apikey check + } else if (apikey === config.org2ApiKey) { + user.org = config.identityNameOrg2; + logger.info('Organisation set to Org2'); + done(null, user); } else { logger.debug({ apikey }, 'No valid X-API-Key'); return done(null, false); @@ -42,7 +43,8 @@ export const authenticateApiKey = ( passport.authenticate( 'headerapikey', { session: false }, - function (err, user, _info) { + (err, user, _info) => { + logger.debug({ user }, 'USERUSERUSER'); if (err) return next(err); if (!user) return res.status(UNAUTHORIZED).json({ @@ -50,7 +52,8 @@ export const authenticateApiKey = ( reason: 'NO_VALID_APIKEY', timestamp: new Date().toISOString(), }); - req.logIn(user, { session: false }, (err) => { + + req.logIn(user, { session: false }, async (err) => { if (err) { return next(err); } diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 08c33865..94c4d998 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -27,14 +27,21 @@ export const asLocalHost = env .example('true') .asBoolStrict(); -export const identityName = 'restServerIdentity'; +export const identityNameOrg1 = 'Org1'; +export const identityNameOrg2 = 'Org2'; -export const mspId = env - .get('HLF_MSP_ID') +const mspIdOrg1 = env + .get('HLF_MSP_ID_ORG1') .default('Org1MSP') .example('Org1MSP') .asString(); +const mspIdOrg2 = env + .get('HLF_MSP_ID_ORG2') + .default('Org2MSP') + .example('Org2MSP') + .asString(); + export const channelName = env .get('HLF_CHANNEL_NAME') .default('mychannel') @@ -59,22 +66,42 @@ export const endorseTimeout = env .example('30') .asIntPositive(); -export const connectionProfile = env - .get('HLF_CONNECTION_PROFILE') +const connectionProfileOrg1 = env + .get('HLF_CONNECTION_PROFILE_ORG1') .required() .example( '{"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... }' ) .asJsonObject(); -export const certificate = env - .get('HLF_CERTIFICATE') +const certificateOrg1 = env + .get('HLF_CERTIFICATE_ORG1') .required() .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') .asString(); -export const privateKey = env - .get('HLF_PRIVATE_KEY') +const privateKeyOrg1 = env + .get('HLF_PRIVATE_KEY_ORG1') + .required() + .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') + .asString(); + +const connectionProfileOrg2 = env + .get('HLF_CONNECTION_PROFILE_ORG2') + .required() + .example( + '{"name":"test-network-org2","version":"1.0.0","client":{"organization":"Org2" ... }' + ) + .asJsonObject(); + +const certificateOrg2 = env + .get('HLF_CERTIFICATE_ORG2') + .required() + .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') + .asString(); + +const privateKeyOrg2 = env + .get('HLF_PRIVATE_KEY_ORG2') .required() .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') .asString(); @@ -103,3 +130,25 @@ export const org1ApiKey = env .required() .example('123') .asString(); + +export const org2ApiKey = env + .get('ORG2_APIKEY') + .required() + .example('456') + .asString(); + +export const ORG1_CONFIG = { + identityName: identityNameOrg1, + mspId: mspIdOrg1, + connectionProfile: connectionProfileOrg1, + certificate: certificateOrg1, + privateKey: privateKeyOrg1, +}; + +export const ORG2_CONFIG = { + identityName: identityNameOrg2, + mspId: mspIdOrg2, + connectionProfile: connectionProfileOrg2, + certificate: certificateOrg2, + privateKey: privateKeyOrg2, +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index d96abe9b..1db73941 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -14,6 +14,7 @@ import { BlockEvent, TransactionEvent, } from 'fabric-network'; +import { Request } from 'express'; import { Redis } from 'ioredis'; import * as config from './config'; import { logger } from './logger'; @@ -31,24 +32,39 @@ export const getNetwork = async (gateway: Gateway): Promise => { return network; }; -export const getGateway = async (): Promise => { +interface FabricConfigType { + identityName: string; + mspId: string; + connectionProfile: { [key: string]: any }; + certificate: string; + privateKey: string; +} + +const FabricDataMapper: { [key: string]: FabricConfigType } = { + [config.identityNameOrg1]: config.ORG1_CONFIG, + [config.identityNameOrg2]: config.ORG2_CONFIG, +}; + +export const getGateway = async (org: string): Promise => { + const fabricConfig = FabricDataMapper[org]; + logger.debug('Configuring fabric gateway for %s', org); const wallet = await Wallets.newInMemoryWallet(); const x509Identity = { credentials: { - certificate: config.certificate, - privateKey: config.privateKey, + certificate: fabricConfig.certificate, + privateKey: fabricConfig.privateKey, }, - mspId: config.mspId, + mspId: fabricConfig.mspId, type: 'X.509', }; - await wallet.put(config.identityName, x509Identity); + await wallet.put(fabricConfig.identityName, x509Identity); const gateway = new Gateway(); const connectOptions: GatewayOptions = { wallet, - identity: config.identityName, + identity: fabricConfig.identityName, discovery: { enabled: true, asLocalhost: config.asLocalHost }, eventHandlerOptions: { commitTimeout: config.commitTimeout, @@ -61,8 +77,7 @@ export const getGateway = async (): Promise => { }, }; - await gateway.connect(config.connectionProfile, connectOptions); - + await gateway.connect(fabricConfig.connectionProfile, connectOptions); return gateway; }; @@ -306,3 +321,10 @@ export const getChainInfo = async (qscc: Contract): Promise => { return false; } }; + +export const getContractForOrg = ( + req: Request +): { contract: Contract; qscc: Contract } => { + const user: { org: string } = req.user as { org: string }; + return req.app.get('fabric')[user.org as string].contracts; +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 9d65028e..94814eb6 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -12,9 +12,11 @@ import { createServer } from './server'; async function main() { const app = await createServer(); - const contract: Contract = app.get('contracts').contract; + const contract: Contract = + app.get('fabric')[config.identityNameOrg1].contracts.contract; const redis: Redis = app.get('redis'); - const network: Network = app.get('network'); + const network: Network = app.get('fabric')[config.identityNameOrg1].network; + await network.addBlockListener(blockEventHandler(redis)); startRetryLoop(contract, redis); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 1b900248..31dc77c7 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -10,10 +10,16 @@ import pinoMiddleware from 'pino-http'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; import { transactionsRouter } from './transactions.router'; -import { getContracts, getGateway, getNetwork, getChainInfo } from './fabric'; +import { + getContracts, + getGateway, + getNetwork, + getChainInfo, + getContractForOrg, +} from './fabric'; import { redis } from './redis'; import { Contract } from 'fabric-network'; - +import * as config from './config'; const { BAD_REQUEST, INTERNAL_SERVER_ERROR, @@ -24,6 +30,7 @@ const { import { authenticateApiKey, fabricAPIKeyStrategy } from './auth'; import passport from 'passport'; + export const createServer = async (): Promise => { const app = express(); @@ -63,13 +70,31 @@ export const createServer = async (): Promise => { if (process.env.NODE_ENV === 'production') { app.use(helmet()); } + // + const gatewayOrg1 = await getGateway(config.identityNameOrg1); + const gatewayOrg2 = await getGateway(config.identityNameOrg2); + const networkOrg1 = await getNetwork(gatewayOrg1); + const networkOrg2 = await getNetwork(gatewayOrg2); + + const contractsOrg1 = await getContracts(networkOrg1); + const contractsOrg2 = await getContracts(networkOrg2); + + const fabric = { + [config.identityNameOrg1]: { + gateway: gatewayOrg1, + contracts: contractsOrg1, + network: networkOrg1, + }, + [config.identityNameOrg2]: { + gateway: gatewayOrg2, + contracts: contractsOrg2, + network: networkOrg2, + }, + }; + + app.set('fabric', fabric); - const gateway = await getGateway(); - const network = await getNetwork(gateway); - const contracts = await getContracts(network); - app.set('contracts', contracts); app.set('redis', redis); - app.set('network', network); // Health routes app.get('/ready', (_req, res) => @@ -79,8 +104,16 @@ export const createServer = async (): Promise => { }) ); app.get('/live', async (_req, res) => { - const qscc: Contract = _req.app.get('contracts').qscc; - if ((await getChainInfo(qscc)) === true) { + _req.user = { org: config.identityNameOrg1 }; + const qsccOrg1: Contract = getContractForOrg(_req).qscc; + const Org1Liveness = await getChainInfo(qsccOrg1); + logger.debug('Org1 liveness %s', Org1Liveness); + _req.user = { org: config.identityNameOrg2 }; + const qsccOrg2: Contract = getContractForOrg(_req).qscc; + const Org2Liveness = await getChainInfo(qsccOrg2); + logger.debug('Org2 liveness %s', Org2Liveness); + + if (Org1Liveness && Org2Liveness) { res.status(OK).json({ status: getReasonPhrase(OK), timestamp: new Date().toISOString(), diff --git a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts index 2a0bc987..c3dd49bf 100644 --- a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts @@ -7,7 +7,7 @@ import { Contract } from 'fabric-network'; import { protos } from 'fabric-protos'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { Redis } from 'ioredis'; -import { evatuateTransaction } from './fabric'; +import { evatuateTransaction, getContractForOrg } from './fabric'; import { logger } from './logger'; import * as config from './config'; import { TransactionNotFoundError } from './errors'; @@ -28,7 +28,7 @@ transactionsRouter.get( let progress: Progress = 'DONE'; let validationCode = ''; - const qscc: Contract = req.app.get('contracts').qscc; + const qscc: Contract = getContractForOrg(req).qscc; const redis: Redis = req.app.get('redis'); try { From 9f48a42418800e6a03b3d20374b7e11d04b7c231 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 26 Jul 2021 12:06:31 +0100 Subject: [PATCH 068/106] Initial test framework Add Jest test framework Signed-off-by: James Taylor --- .../rest-api-typescript/jest.config.ts | 192 + .../rest-api-typescript/package-lock.json | 3825 ++++++++++++++++- .../rest-api-typescript/package.json | 10 +- .../src/__mocks__/config.ts | 55 + .../src/__mocks__/fabric-network.ts | 41 + .../src/__tests__/api.test.ts | 31 + .../rest-api-typescript/src/config.ts | 33 +- .../rest-api-typescript/src/fabric.ts | 20 +- .../rest-api-typescript/src/server.ts | 4 + 9 files changed, 4180 insertions(+), 31 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/jest.config.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts diff --git a/asset-transfer-basic/rest-api-typescript/jest.config.ts b/asset-transfer-basic/rest-api-typescript/jest.config.ts new file mode 100644 index 00000000..ba3bbbc4 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/jest.config.ts @@ -0,0 +1,192 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ + +export default { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/04/rqvxpdk52gvf1_qq9l8gt4d40000gn/T/jest_dx", + + // Automatically clear mock calls and instances between every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: 'coverage', + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'v8', + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + preset: 'ts-jest', + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state between every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state between every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + roots: ['/src'], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + // testEnvironment: "jest-environment-node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + '**/?(*.)+(spec|test).[tj]s?(x)', + ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index 4e25209a..4270a380 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -13,12 +13,251 @@ "@babel/highlight": "^7.10.4" } }, + "@babel/compat-data": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", + "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==", + "dev": true + }, + "@babel/core": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.8.tgz", + "integrity": "sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.8", + "@babel/helper-compilation-targets": "^7.14.5", + "@babel/helper-module-transforms": "^7.14.8", + "@babel/helpers": "^7.14.8", + "@babel/parser": "^7.14.8", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.8", + "@babel/types": "^7.14.8", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.8.tgz", + "integrity": "sha512-cYDUpvIzhBVnMzRoY1fkSEhK/HmwEVwlyULYgn/tMQYd6Obag3ylCjONle3gdErfXBW61SVTlR9QR7uWlgeIkg==", + "dev": true, + "requires": { + "@babel/types": "^7.14.8", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", + "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", + "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.14.5", + "@babel/template": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", + "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", + "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", + "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", + "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.8.tgz", + "integrity": "sha512-RyE+NFOjXn5A9YU1dkpeBaduagTlZ0+fccnIcAGbv1KGUlReBj7utF7oEth8IdIBQPcux0DDgW5MFBH2xu9KcA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5", + "@babel/helper-simple-access": "^7.14.8", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.8", + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.8", + "@babel/types": "^7.14.8" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz", + "integrity": "sha512-ZGy6/XQjllhYQrNw/3zfWRwZCTVSiBLZ9DHVZxn9n2gip/7ab8mv2TWlKPIBk26RwedCBoWdjLmn+t9na2Gcow==", + "dev": true + } + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", + "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", + "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-optimise-call-expression": "^7.14.5", + "@babel/traverse": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", + "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", + "dev": true, + "requires": { + "@babel/types": "^7.14.8" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", + "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", + "dev": true, + "requires": { + "@babel/types": "^7.14.5" + } + }, "@babel/helper-validator-identifier": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", "dev": true }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "dev": true + }, + "@babel/helpers": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz", + "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==", + "dev": true, + "requires": { + "@babel/template": "^7.14.5", + "@babel/traverse": "^7.14.8", + "@babel/types": "^7.14.8" + } + }, "@babel/highlight": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", @@ -49,6 +288,224 @@ } } }, + "@babel/parser": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.8.tgz", + "integrity": "sha512-syoCQFOoo/fzkWDeM0dLEZi5xqurb5vuyzwIMNZRNun+N/9A4cUZeQaE7dTrB8jGaKuJRBtEOajtnmw0I5hvvA==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/template": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", + "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + } + } + }, + "@babel/traverse": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.8.tgz", + "integrity": "sha512-kexHhzCljJcFNn1KYAQ6A5wxMRzq9ebYpEDV4+WdNyr3i7O44tanbDOR/xjiG2F3sllan+LgwK+7OMk0EmydHg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.14.8", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.14.8", + "@babel/types": "^7.14.8", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.8.tgz", + "integrity": "sha512-iob4soQa7dZw8nodR/KlOQkPh9S4I8RwCxwRIFuiMRYjOzH/KJzdUfDgz6cGi5dDaclXF4P2PAhCdrBJNIg68Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.8", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz", + "integrity": "sha512-ZGy6/XQjllhYQrNw/3zfWRwZCTVSiBLZ9DHVZxn9n2gip/7ab8mv2TWlKPIBk26RwedCBoWdjLmn+t9na2Gcow==", + "dev": true + } + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "@eslint/eslintrc": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", @@ -115,6 +572,422 @@ "integrity": "sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg==", "dev": true }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.0.6.tgz", + "integrity": "sha512-fMlIBocSHPZ3JxgWiDNW/KPj6s+YRd0hicb33IrmelCcjXo/pXPwvuiKFmZz+XuqI/1u7nbUK10zSsWL/1aegg==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.0.6", + "jest-util": "^27.0.6", + "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/core": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.0.6.tgz", + "integrity": "sha512-SsYBm3yhqOn5ZLJCtccaBcvD/ccTLCeuDv8U41WJH/V1MW5eKUkeMHT9U+Pw/v1m1AIWlnIW/eM2XzQr0rEmow==", + "dev": true, + "requires": { + "@jest/console": "^27.0.6", + "@jest/reporters": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^27.0.6", + "jest-config": "^27.0.6", + "jest-haste-map": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-resolve-dependencies": "^27.0.6", + "jest-runner": "^27.0.6", + "jest-runtime": "^27.0.6", + "jest-snapshot": "^27.0.6", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", + "jest-watcher": "^27.0.6", + "micromatch": "^4.0.4", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/environment": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.0.6.tgz", + "integrity": "sha512-4XywtdhwZwCpPJ/qfAkqExRsERW+UaoSRStSHCCiQTUpoYdLukj+YJbQSFrZjhlUDRZeNiU9SFH0u7iNimdiIg==", + "dev": true, + "requires": { + "@jest/fake-timers": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/node": "*", + "jest-mock": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/fake-timers": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.0.6.tgz", + "integrity": "sha512-sqd+xTWtZ94l3yWDKnRTdvTeZ+A/V7SSKrxsrOKSqdyddb9CeNRF8fbhAU0D7ZJBpTTW2nbp6MftmKJDZfW2LQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@sinonjs/fake-timers": "^7.0.2", + "@types/node": "*", + "jest-message-util": "^27.0.6", + "jest-mock": "^27.0.6", + "jest-util": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/globals": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.0.6.tgz", + "integrity": "sha512-DdTGCP606rh9bjkdQ7VvChV18iS7q0IMJVP1piwTWyWskol4iqcVwthZmoJEf7obE1nc34OpIyoVGPeqLC+ryw==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.6", + "@jest/types": "^27.0.6", + "expect": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/reporters": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.0.6.tgz", + "integrity": "sha512-TIkBt09Cb2gptji3yJXb3EE+eVltW6BjO7frO7NEfjI9vSIYoISi5R3aI3KpEDXlB1xwB+97NXIqz84qYeYsfA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-util": "^27.0.6", + "jest-worker": "^27.0.6", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/source-map": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.0.6.tgz", + "integrity": "sha512-ja/pBOMTufjX4JLEauLxE3LQBPaI2YjGFtXexRAjt1I/MbfNlMx0sytSX3tn5hSLzQsR3Qy2rd0hc1BWojtj9w==", + "dev": true, + "requires": { + "@jest/console": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/test-sequencer": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.0.6.tgz", + "integrity": "sha512-bISzNIApazYOlTHDum9PwW22NOyDa6VI31n6JucpjTVM0jD6JDgqEZ9+yn575nDdPF0+4csYDxNNW13NvFQGZA==", + "dev": true, + "requires": { + "@jest/test-result": "^27.0.6", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.6", + "jest-runtime": "^27.0.6" + } + }, + "@jest/transform": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.0.6.tgz", + "integrity": "sha512-rj5Dw+mtIcntAUnMlW/Vju5mr73u8yg+irnHwzgtgoeI6cCPOvUwQ0D1uQtc/APmWgvRweEb1g05pkUpxH3iCA==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.0.6", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.0.6", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -195,6 +1068,95 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.15", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz", + "integrity": "sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, "@types/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", @@ -214,6 +1176,12 @@ "@types/node": "*" } }, + "@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, "@types/express": { "version": "4.17.12", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", @@ -237,6 +1205,15 @@ "@types/range-parser": "*" } }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/ioredis": { "version": "4.26.4", "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.26.4.tgz", @@ -246,6 +1223,40 @@ "@types/node": "*" } }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "26.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", + "dev": true, + "requires": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, "@types/json-schema": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", @@ -316,6 +1327,12 @@ "@types/node": "*" } }, + "@types/prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", + "dev": true + }, "@types/qs": { "version": "6.9.6", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", @@ -347,11 +1364,51 @@ "@types/node": "*" } }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/superagent": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.12.tgz", + "integrity": "sha512-1GQvD6sySQPD6p9EopDFI3f5OogdICl1sU/2ij3Esobz/RtL9fWZZDPmsuv7eiy5ya+XNiPAxUcI3HIUTJa+3A==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "@types/supertest": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.11.tgz", + "integrity": "sha512-uci4Esokrw9qGb9bvhhSVEjd6rkny/dk5PK/Qz4yxKiyppEI+dOPlNrZBahE3i+PoKFYyDxChVXZ/ysS/nrm1Q==", + "dev": true, + "requires": { + "@types/superagent": "*" + } + }, "@types/tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" }, + "@types/yargs": { + "version": "15.0.14", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", + "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "4.28.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz", @@ -485,6 +1542,12 @@ "eslint-visitor-keys": "^2.0.0" } }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -500,12 +1563,54 @@ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, "acorn-jsx": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "dev": true }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -524,6 +1629,23 @@ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", @@ -538,6 +1660,22 @@ "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -600,6 +1738,12 @@ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, "atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -622,6 +1766,101 @@ "pify": "^5.0.0" } }, + "babel-jest": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.0.6.tgz", + "integrity": "sha512-iTJyYLNc4wRofASmofpOc5NK9QunwMk+TLFgGXsTFS8uEqmd8wdI7sga0FPe2oVH3b5Agt/EAK1QjPEuKL8VfA==", + "dev": true, + "requires": { + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.0.6", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz", + "integrity": "sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz", + "integrity": "sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.0.6", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -674,6 +1913,43 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -710,6 +1986,12 @@ "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", "dev": true }, + "caniuse-lite": { + "version": "1.0.30001248", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001248.tgz", + "integrity": "sha512-NwlQbJkxUFJ8nMErnGtT0QTM2TJ33xgz4KXJSMIrjXIbDVdaYueGyjOrLKRtJC+rTiWfi6j5cnZN1NBiSBJGNw==", + "dev": true + }, "chalk": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", @@ -761,6 +2043,24 @@ } } }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -776,6 +2076,18 @@ "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -791,11 +2103,32 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, "colors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -815,6 +2148,15 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", @@ -825,6 +2167,18 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -836,11 +2190,45 @@ "which": "^2.0.1" } }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, "cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, "dateformat": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.5.1.tgz", @@ -855,12 +2243,36 @@ "ms": "2.0.0" } }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "denque": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", @@ -876,6 +2288,24 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -894,6 +2324,23 @@ "esutils": "^2.0.2" } }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, "dotenv": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", @@ -904,6 +2351,12 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "electron-to-chromium": { + "version": "1.3.789", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.789.tgz", + "integrity": "sha512-lK4xn6C6ZF1kgLaC/EhOtC1MSKENExj3rMwGVnBTfHW81Z/Hb1Rge5YaWawN/YOXy3xCaESuE4KWSD50kOZ9rQ==", + "dev": true + }, "elliptic": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", @@ -925,6 +2378,12 @@ } } }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -974,6 +2433,66 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, "eslint": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz", @@ -1177,6 +2696,79 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expect": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.6.tgz", + "integrity": "sha512-psNLt8j2kwg42jGBDSfAlU49CEZxejN1f1PlANWDZqIhBOVU/c2Pm888FcjWJzFewhIsNWfZJeLjUjtKGiPuSw==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.0.6", + "jest-matcher-utils": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-regex-util": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "jest-get-type": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "dev": true + } + } + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -1333,6 +2925,15 @@ "reusify": "^1.0.4" } }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1365,6 +2966,16 @@ "unpipe": "~1.0.0" } }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -1391,6 +3002,23 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", + "dev": true + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1407,6 +3035,13 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -1418,6 +3053,12 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1433,6 +3074,18 @@ "has-symbols": "^1.0.1" } }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -1479,6 +3132,12 @@ "slash": "^3.0.0" } }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1522,6 +3181,21 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -1534,11 +3208,72 @@ "toidentifier": "1.0.0" } }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "http-status-codes": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.1.4.tgz", "integrity": "sha512-MZVIsLKGVOVE1KEnldppe6Ij+vmemMuApDfjhVSLzyYP+td0bREEYyAoIw9yFePoBXManCuBqmiNP5FqJS5Xkg==" }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -1563,6 +3298,16 @@ "resolve-from": "^4.0.0" } }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1626,6 +3371,24 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "is-core-module": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", + "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1637,6 +3400,12 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -1652,11 +3421,29 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1668,6 +3455,1337 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", + "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", + "dev": true, + "requires": { + "@jest/core": "^27.0.6", + "import-local": "^3.0.2", + "jest-cli": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-cli": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.0.6.tgz", + "integrity": "sha512-qUUVlGb9fdKir3RDE+B10ULI+LQrz+MCflEH2UJyoUjoHHCbxDrMxSzjQAPUMsic4SncI62ofYCcAvW6+6rhhg==", + "dev": true, + "requires": { + "@jest/core": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/types": "^27.0.6", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.0.6", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", + "prompts": "^2.0.1", + "yargs": "^16.0.3" + } + } + } + }, + "jest-changed-files": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.0.6.tgz", + "integrity": "sha512-BuL/ZDauaq5dumYh5y20sn4IISnf1P9A0TDswTxUi84ORGtVa86ApuBHqICL0vepqAnZiY6a7xeSPWv2/yy4eA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-circus": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.0.6.tgz", + "integrity": "sha512-OJlsz6BBeX9qR+7O9lXefWoc2m9ZqcZ5Ohlzz0pTEAG4xMiZUJoacY8f4YDHxgk0oKYxj277AfOk9w6hZYvi1Q==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.0.6", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.0.6", + "jest-matcher-utils": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-runtime": "^27.0.6", + "jest-snapshot": "^27.0.6", + "jest-util": "^27.0.6", + "pretty-format": "^27.0.6", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-config": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.0.6.tgz", + "integrity": "sha512-JZRR3I1Plr2YxPBhgqRspDE2S5zprbga3swYNrvY3HfQGu7p/GjyLOqwrYad97tX3U3mzT53TPHVmozacfP/3w==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.0.6", + "@jest/types": "^27.0.6", + "babel-jest": "^27.0.6", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "jest-circus": "^27.0.6", + "jest-environment-jsdom": "^27.0.6", + "jest-environment-node": "^27.0.6", + "jest-get-type": "^27.0.6", + "jest-jasmine2": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-runner": "^27.0.6", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", + "micromatch": "^4.0.4", + "pretty-format": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "jest-get-type": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-diff": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + } + }, + "jest-docblock": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.6.tgz", + "integrity": "sha512-m6yKcV3bkSWrUIjxkE9OC0mhBZZdhovIW5ergBYirqnkLXkyEn3oUUF/QZgyecA1cF1QFyTE8bRRl8Tfg1pfLA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "chalk": "^4.0.0", + "jest-get-type": "^27.0.6", + "jest-util": "^27.0.6", + "pretty-format": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "jest-get-type": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-environment-jsdom": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.0.6.tgz", + "integrity": "sha512-FvetXg7lnXL9+78H+xUAsra3IeZRTiegA3An01cWeXBspKXUhAwMM9ycIJ4yBaR0L7HkoMPaZsozCLHh4T8fuw==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.6", + "@jest/fake-timers": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/node": "*", + "jest-mock": "^27.0.6", + "jest-util": "^27.0.6", + "jsdom": "^16.6.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-environment-node": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.0.6.tgz", + "integrity": "sha512-+Vi6yLrPg/qC81jfXx3IBlVnDTI6kmRr08iVa2hFCWmJt4zha0XW7ucQltCAPhSR0FEKEoJ3i+W4E6T0s9is0w==", + "dev": true, + "requires": { + "@jest/environment": "^27.0.6", + "@jest/fake-timers": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/node": "*", + "jest-mock": "^27.0.6", + "jest-util": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-get-type": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "dev": true + }, + "jest-haste-map": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.0.6.tgz", + "integrity": "sha512-4ldjPXX9h8doB2JlRzg9oAZ2p6/GpQUNAeiYXqcpmrKbP0Qev0wdZlxSMOmz8mPOEnt4h6qIzXFLDi8RScX/1w==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.0.6", + "jest-worker": "^27.0.6", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-jasmine2": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.0.6.tgz", + "integrity": "sha512-cjpH2sBy+t6dvCeKBsHpW41mjHzXgsavaFMp+VWRf0eR4EW8xASk1acqmljFtK2DgyIECMv2yCdY41r2l1+4iA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^27.0.6", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.0.6", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.0.6", + "jest-matcher-utils": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-runtime": "^27.0.6", + "jest-snapshot": "^27.0.6", + "jest-util": "^27.0.6", + "pretty-format": "^27.0.6", + "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-leak-detector": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.0.6.tgz", + "integrity": "sha512-2/d6n2wlH5zEcdctX4zdbgX8oM61tb67PQt4Xh8JFAIy6LRKUnX528HulkaG6nD5qDl5vRV1NXejCe1XRCH5gQ==", + "dev": true, + "requires": { + "jest-get-type": "^27.0.6", + "pretty-format": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "jest-get-type": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-matcher-utils": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.6.tgz", + "integrity": "sha512-OFgF2VCQx9vdPSYTHWJ9MzFCehs20TsyFi6bIHbk5V1u52zJOnvF0Y/65z3GLZHKRuTgVPY4Z6LVePNahaQ+tA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.0.6", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "diff-sequences": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "dev": true + }, + "jest-diff": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz", + "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.0.6" + } + }, + "jest-get-type": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-message-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.6.tgz", + "integrity": "sha512-rBxIs2XK7rGy+zGxgi+UJKP6WqQ+KrBbD1YMj517HYN3v2BG66t3Xan3FWqYHKZwjdB700KiAJ+iES9a0M+ixw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.0.6", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.0.6", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-mock": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.0.6.tgz", + "integrity": "sha512-lzBETUoK8cSxts2NYXSBWT+EJNzmUVtVVwS1sU9GwE1DLCfGsngg+ZVSIe0yd0ZSm+y791esiuo+WSwpXJQ5Bw==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true + }, + "jest-regex-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", + "dev": true + }, + "jest-resolve": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.0.6.tgz", + "integrity": "sha512-yKmIgw2LgTh7uAJtzv8UFHGF7Dm7XfvOe/LQ3Txv101fLM8cx2h1QVwtSJ51Q/SCxpIiKfVn6G2jYYMDNHZteA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "chalk": "^4.0.0", + "escalade": "^3.1.1", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", + "resolve": "^1.20.0", + "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.0.6.tgz", + "integrity": "sha512-mg9x9DS3BPAREWKCAoyg3QucCr0n6S8HEEsqRCKSPjPcu9HzRILzhdzY3imsLoZWeosEbJZz6TKasveczzpJZA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-runner": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.0.6.tgz", + "integrity": "sha512-W3Bz5qAgaSChuivLn+nKOgjqNxM7O/9JOJoKDCqThPIg2sH/d4A/lzyiaFgnb9V1/w29Le11NpzTJSzga1vyYQ==", + "dev": true, + "requires": { + "@jest/console": "^27.0.6", + "@jest/environment": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.0.6", + "jest-environment-node": "^27.0.6", + "jest-haste-map": "^27.0.6", + "jest-leak-detector": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-runtime": "^27.0.6", + "jest-util": "^27.0.6", + "jest-worker": "^27.0.6", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-runtime": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.0.6.tgz", + "integrity": "sha512-BhvHLRVfKibYyqqEFkybsznKwhrsu7AWx2F3y9G9L95VSIN3/ZZ9vBpm/XCS2bS+BWz3sSeNGLzI3TVQ0uL85Q==", + "dev": true, + "requires": { + "@jest/console": "^27.0.6", + "@jest/environment": "^27.0.6", + "@jest/fake-timers": "^27.0.6", + "@jest/globals": "^27.0.6", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.0.6", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-mock": "^27.0.6", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-snapshot": "^27.0.6", + "jest-util": "^27.0.6", + "jest-validate": "^27.0.6", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^16.0.3" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-serializer": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-snapshot": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.0.6.tgz", + "integrity": "sha512-NTHaz8He+ATUagUgE7C/UtFcRoHqR2Gc+KDfhQIyx+VFgwbeEMjeP+ILpUTLosZn/ZtbNdCF5LkVnN/l+V751A==", + "dev": true, + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.0.6", + "graceful-fs": "^4.2.4", + "jest-diff": "^27.0.6", + "jest-get-type": "^27.0.6", + "jest-haste-map": "^27.0.6", + "jest-matcher-utils": "^27.0.6", + "jest-message-util": "^27.0.6", + "jest-resolve": "^27.0.6", + "jest-util": "^27.0.6", + "natural-compare": "^1.4.0", + "pretty-format": "^27.0.6", + "semver": "^7.3.2" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "diff-sequences": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "dev": true + }, + "jest-diff": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz", + "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.0.6" + } + }, + "jest-get-type": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.6.tgz", + "integrity": "sha512-1JjlaIh+C65H/F7D11GNkGDDZtDfMEM8EBXsvd+l/cxtgQ6QhxuloOaiayt89DxUvDarbVhqI98HhgrM1yliFQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-validate": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.0.6.tgz", + "integrity": "sha512-yhZZOaMH3Zg6DC83n60pLmdU1DQE46DW+KLozPiPbSbPhlXXaiUTDlhHQhHFpaqIFRrInko1FHXjTRpjWRuWfA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.0.6", + "leven": "^3.1.0", + "pretty-format": "^27.0.6" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "jest-get-type": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "pretty-format": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz", + "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==", + "dev": true, + "requires": { + "@jest/types": "^27.0.6", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } + } + }, + "jest-watcher": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.0.6.tgz", + "integrity": "sha512-/jIoKBhAP00/iMGnTwUBLgvxkn7vsOweDrOTSPzc7X9uOyUtJIDthQBTI1EXz90bdkrxorUZVhJwiB69gcHtYQ==", + "dev": true, + "requires": { + "@jest/test-result": "^27.0.6", + "@jest/types": "^27.0.6", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.0.6", + "string-length": "^4.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz", + "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } + }, + "jest-worker": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.6.tgz", + "integrity": "sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", @@ -1701,6 +4819,55 @@ "esprima": "^4.0.0" } }, + "jsdom": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.6.0.tgz", + "integrity": "sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.5", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "dev": true + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1713,11 +4880,26 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "jsrsasign": { "version": "8.0.24", "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-8.0.24.tgz", "integrity": "sha512-u45jAyusqUpyGbFc2IbHoeE4rSkoBWQgLe/w99temHenX+GyCz4nflU5sjK7ajU1ffZTezl6le7u43Yjr/lkQg==" }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, "leven": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", @@ -1734,6 +4916,15 @@ "type-check": "~0.4.0" } }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1786,6 +4977,38 @@ "yallist": "^4.0.0" } }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1796,6 +5019,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -1835,6 +5064,12 @@ "mime-db": "1.48.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -1854,6 +5089,18 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, "mri": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", @@ -1915,6 +5162,45 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, "object-inspect": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", @@ -1937,6 +5223,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -1951,11 +5246,41 @@ "word-wrap": "^1.2.3" } }, + "p-each-series": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, "p-map": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1965,6 +5290,12 @@ "callsites": "^3.0.0" } }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1993,6 +5324,12 @@ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2005,6 +5342,12 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -2088,6 +5431,15 @@ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz", "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==" }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, "pkcs11js": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/pkcs11js/-/pkcs11js-1.2.5.tgz", @@ -2097,6 +5449,15 @@ "nan": "^2.14.2" } }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2118,6 +5479,44 @@ "fast-diff": "^1.1.2" } }, + "pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -2129,6 +5528,16 @@ "resolved": "https://registry.npmjs.org/promise-settle/-/promise-settle-0.3.0.tgz", "integrity": "sha1-tO/VcqHrdM95T4KM00naQKCOTpY=" }, + "prompts": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", + "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "protobufjs": { "version": "6.11.2", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", @@ -2210,6 +5619,12 @@ "unpipe": "1.0.0" } }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -2256,6 +5671,33 @@ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2302,6 +5744,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "secure-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz", @@ -2384,6 +5835,18 @@ "object-inspect": "^1.9.0" } }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "sjcl": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", @@ -2475,6 +5938,23 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "standard-as-callback": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", @@ -2485,6 +5965,16 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, "string-width": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", @@ -2520,12 +6010,85 @@ "ansi-regex": "^5.0.0" } }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "superagent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", + "dev": true, + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, + "supertest": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.1.4.tgz", + "integrity": "sha512-giC9Zm+Bf1CZP09ciPdUyl+XlMAu6rbch79KYiYKOGcbK2R1wH8h+APul1i/3wN6RF1XfWOIF+8X1ga+7SBrug==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^6.1.0" + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -2535,6 +6098,39 @@ "has-flag": "^3.0.0" } }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "table": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", @@ -2569,12 +6165,51 @@ } } }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2606,6 +6241,67 @@ } } }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + } + } + }, + "ts-jest": { + "version": "27.0.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.4.tgz", + "integrity": "sha512-c4E1ECy9Xz2WGfTMyHbSaArlIva7Wi2p43QOMmCqjSSjHP06KXv+aT+eSY+yZMuqsMi3k7pyGsGj2q5oSl5WfQ==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash": "4.x", + "make-error": "1.x", + "mkdirp": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + } + }, + "ts-node": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.1.0.tgz", + "integrity": "sha512-6szn3+J9WyG2hE+5W8e0ruZrzyk1uFLYye6IGMBadnOzDh8aP7t8CbFpsfCiEx2+wMixAhjFt7lOZC4+l+WbEA==", + "dev": true, + "requires": { + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -2630,6 +6326,12 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -2645,10 +6347,19 @@ "mime-types": "~2.1.24" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", - "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", "dev": true }, "universalify": { @@ -2695,6 +6406,25 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "v8-to-istanbul": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz", + "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, "validator": { "version": "13.6.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", @@ -2705,6 +6435,65 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2779,6 +6568,36 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", + "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index 1b1aa0e6..328e5f45 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -21,19 +21,25 @@ "devDependencies": { "@types/express": "^4.17.12", "@types/ioredis": "^4.26.4", + "@types/jest": "^26.0.24", "@types/node": "^15.12.4", "@types/passport": "^1.0.7", "@types/pino": "^6.3.8", "@types/pino-http": "^5.4.1", + "@types/supertest": "^2.0.11", "@typescript-eslint/eslint-plugin": "^4.28.0", "@typescript-eslint/parser": "^4.28.0", "eslint": "^7.29.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^3.4.0", + "jest": "^27.0.6", "pino-pretty": "^5.0.2", "prettier": "^2.3.1", "rimraf": "^3.0.2", - "typescript": "^4.3.4" + "supertest": "^6.1.4", + "ts-jest": "^27.0.4", + "ts-node": "^10.1.0", + "typescript": "^4.3.5" }, "scripts": { "prebuild": "npm run lint", @@ -45,7 +51,7 @@ "start": "node --require source-map-support/register ./dist", "start:dev": "node --require source-map-support/register --require dotenv/config ./dist | pino-pretty", "start:redis": "docker run -p 6379:6379 --name fabric-sample-redis -d redis", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "jest" }, "author": "Hyperledger", "license": "Apache-2.0", diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts new file mode 100644 index 00000000..b3a2bc44 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +export const logLevel = 'info'; + +export const port = '3000'; + +export const retryDelay = '3000'; + +export const asLocalHost = true; + +export const identityNameOrg1 = 'Org1'; + +export const identityNameOrg2 = 'Org2'; + +export const mspIdOrg1 = 'Org1MSP'; + +export const mspIdOrg2 = 'Org2MSP'; + +export const channelName = 'mychannel'; + +export const chaincodeName = 'basic'; + +export const commitTimeout = '3000'; + +export const endorseTimeout = '30'; + +export const connectionProfileOrg1 = '{"name":"mock-profile-org1"}'; + +export const certificateOrg1 = + '"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"'; + +export const privateKeyOrg1 = + '"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"'; + +export const connectionProfileOrg2 = '{"name":"mock-profile-org2"}'; + +export const certificateOrg2 = + '"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"'; + +export const privateKeyOrg2 = + '"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"'; + +export const redisHost = 'localhost'; + +export const redisPort = '6379'; + +export const redisUsername = 'conga'; + +export const redisPassword = ''; + +export const org1ApiKey = '123'; + +export const org2ApiKey = '456'; diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts new file mode 100644 index 00000000..216baff7 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { mocked } from 'ts-jest/utils'; + +type FabricNetworkModule = jest.Mocked; + +const { + DefaultEventHandlerStrategies, + DefaultQueryHandlerStrategies, + Gateway, + Wallet, + Wallets, +}: FabricNetworkModule = jest.createMockFromModule('fabric-network'); + +mocked(Wallets.newInMemoryWallet).mockResolvedValue( + new Wallet({ + get: jest.fn(), + list: jest.fn(), + put: jest.fn(), + remove: jest.fn(), + }) +); + +mocked(Gateway.prototype.getNetwork).mockResolvedValue({ + getGateway: jest.fn(), + getContract: jest.fn(), + getChannel: jest.fn(), + addCommitListener: jest.fn(), + removeCommitListener: jest.fn(), + addBlockListener: jest.fn(), + removeBlockListener: jest.fn(), +}); + +export { + DefaultEventHandlerStrategies, + DefaultQueryHandlerStrategies, + Gateway, + Wallets, +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts new file mode 100644 index 00000000..5e0366b2 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createServer } from '../server'; +import { Application } from 'express'; +import request from 'supertest'; + +jest.mock('../config'); +jest.mock('fabric-network'); +jest.mock('ioredis'); + +describe('Asset Transfer Besic REST API', () => { + let app: Application; + + beforeEach(async () => { + app = await createServer(); + }); + + describe('GET /ready', () => { + it('should respond with success json', async () => { + const response = await request(app).get('/ready'); + expect(response.statusCode).toEqual(200); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body.status).toEqual('OK'); + }); + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 94c4d998..cc1b4216 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -28,15 +28,16 @@ export const asLocalHost = env .asBoolStrict(); export const identityNameOrg1 = 'Org1'; + export const identityNameOrg2 = 'Org2'; -const mspIdOrg1 = env +export const mspIdOrg1 = env .get('HLF_MSP_ID_ORG1') .default('Org1MSP') .example('Org1MSP') .asString(); -const mspIdOrg2 = env +export const mspIdOrg2 = env .get('HLF_MSP_ID_ORG2') .default('Org2MSP') .example('Org2MSP') @@ -66,7 +67,7 @@ export const endorseTimeout = env .example('30') .asIntPositive(); -const connectionProfileOrg1 = env +export const connectionProfileOrg1 = env .get('HLF_CONNECTION_PROFILE_ORG1') .required() .example( @@ -74,19 +75,19 @@ const connectionProfileOrg1 = env ) .asJsonObject(); -const certificateOrg1 = env +export const certificateOrg1 = env .get('HLF_CERTIFICATE_ORG1') .required() .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') .asString(); -const privateKeyOrg1 = env +export const privateKeyOrg1 = env .get('HLF_PRIVATE_KEY_ORG1') .required() .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') .asString(); -const connectionProfileOrg2 = env +export const connectionProfileOrg2 = env .get('HLF_CONNECTION_PROFILE_ORG2') .required() .example( @@ -94,13 +95,13 @@ const connectionProfileOrg2 = env ) .asJsonObject(); -const certificateOrg2 = env +export const certificateOrg2 = env .get('HLF_CERTIFICATE_ORG2') .required() .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') .asString(); -const privateKeyOrg2 = env +export const privateKeyOrg2 = env .get('HLF_PRIVATE_KEY_ORG2') .required() .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') @@ -136,19 +137,3 @@ export const org2ApiKey = env .required() .example('456') .asString(); - -export const ORG1_CONFIG = { - identityName: identityNameOrg1, - mspId: mspIdOrg1, - connectionProfile: connectionProfileOrg1, - certificate: certificateOrg1, - privateKey: privateKeyOrg1, -}; - -export const ORG2_CONFIG = { - identityName: identityNameOrg2, - mspId: mspIdOrg2, - connectionProfile: connectionProfileOrg2, - certificate: certificateOrg2, - privateKey: privateKeyOrg2, -}; diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 1db73941..4e642700 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -40,9 +40,25 @@ interface FabricConfigType { privateKey: string; } +const ORG1_CONFIG = { + identityName: config.identityNameOrg1, + mspId: config.mspIdOrg1, + connectionProfile: config.connectionProfileOrg1, + certificate: config.certificateOrg1, + privateKey: config.privateKeyOrg1, +}; + +const ORG2_CONFIG = { + identityName: config.identityNameOrg2, + mspId: config.mspIdOrg2, + connectionProfile: config.connectionProfileOrg2, + certificate: config.certificateOrg2, + privateKey: config.privateKeyOrg2, +}; + const FabricDataMapper: { [key: string]: FabricConfigType } = { - [config.identityNameOrg1]: config.ORG1_CONFIG, - [config.identityNameOrg2]: config.ORG2_CONFIG, + [config.identityNameOrg1]: ORG1_CONFIG, + [config.identityNameOrg2]: ORG2_CONFIG, }; export const getGateway = async (org: string): Promise => { diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 31dc77c7..5caf5799 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -67,6 +67,10 @@ export const createServer = async (): Promise => { // TBC } + if (process.env.NODE_ENV === 'test') { + // TBC + } + if (process.env.NODE_ENV === 'production') { app.use(helmet()); } From 4277f4a68f08198a2bf84b9afdec3ab7d7b101a0 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 2 Aug 2021 16:04:23 +0100 Subject: [PATCH 069/106] Fix dist output The jest.config.ts file was causing unintended changes to the dist folder Signed-off-by: James Taylor --- .../rest-api-typescript/.eslintrc.json | 13 ++++++++++--- .../rest-api-typescript/tsconfig.json | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/.eslintrc.json b/asset-transfer-basic/rest-api-typescript/.eslintrc.json index 0eaa9dde..7fcdea66 100644 --- a/asset-transfer-basic/rest-api-typescript/.eslintrc.json +++ b/asset-transfer-basic/rest-api-typescript/.eslintrc.json @@ -10,8 +10,7 @@ "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 12, - "sourceType": "module", - "project": "./tsconfig.json" + "sourceType": "module" }, "plugins": [ "@typescript-eslint" @@ -23,5 +22,13 @@ "argsIgnorePattern": "^_" } ] - } + }, + "overrides": [ + { + "files": ["src/**/*.ts"], + "parserOptions": { + "project": ["./tsconfig.json"] + } + } + ] } diff --git a/asset-transfer-basic/rest-api-typescript/tsconfig.json b/asset-transfer-basic/rest-api-typescript/tsconfig.json index c0e23f1c..cb4a4a82 100644 --- a/asset-transfer-basic/rest-api-typescript/tsconfig.json +++ b/asset-transfer-basic/rest-api-typescript/tsconfig.json @@ -68,5 +68,8 @@ /* Advanced Options */ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - } + }, + "include": [ + "src/" + ] } From 73049e01536c7a89a20a3917f991d1c293216d87 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Tue, 3 Aug 2021 12:38:27 +0530 Subject: [PATCH 070/106] docker file for app readme update for docker added dockerignore added dumb-init env var added to compose readme update Signed-off-by: sapthasurendran --- README.md | 19 ++++++++++++++ .../rest-api-typescript/.dockerignore | 4 +++ .../rest-api-typescript/Dockerfile | 20 ++++++++++++++ .../rest-api-typescript/docker-compose.yaml | 26 +++++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 asset-transfer-basic/rest-api-typescript/.dockerignore create mode 100644 asset-transfer-basic/rest-api-typescript/Dockerfile create mode 100644 asset-transfer-basic/rest-api-typescript/docker-compose.yaml diff --git a/README.md b/README.md index f8ba15c9..b5f40edf 100644 --- a/README.md +++ b/README.md @@ -105,3 +105,22 @@ curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${ ```shell curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request DELETE http://localhost:3000/api/assets/asset7 ``` +## Steps to run the application using docker: + +Move to directory fabric-rest-sample/asset-transfer-basic/rest-api-typescript + +### Build docker image + docker build -t fabricapp . + +### Generate .env file + TEST_NETWORK_HOME=$HOME/fabric-samples/test-network ./scripts/generateEnv.sh + + Note: Connection profile need to use the peer container’s hostname instead of localhost. + +### Run docker containers + docker-compose up -d + + + + + diff --git a/asset-transfer-basic/rest-api-typescript/.dockerignore b/asset-transfer-basic/rest-api-typescript/.dockerignore new file mode 100644 index 00000000..4f3089df --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/.dockerignore @@ -0,0 +1,4 @@ +node_modules +npm-debug.log +Dockerfile +.gitignore diff --git a/asset-transfer-basic/rest-api-typescript/Dockerfile b/asset-transfer-basic/rest-api-typescript/Dockerfile new file mode 100644 index 00000000..5ebc77bd --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/Dockerfile @@ -0,0 +1,20 @@ +FROM node:14-alpine3.12 +RUN apk add dumb-init +WORKDIR /fabric_app/ + +COPY --chown=node:node . /fabric_app/ + +RUN npm ci + +RUN npm run build + +EXPOSE 3000 + +USER node +CMD dumb-init npm run start:dev + + + + + + diff --git a/asset-transfer-basic/rest-api-typescript/docker-compose.yaml b/asset-transfer-basic/rest-api-typescript/docker-compose.yaml new file mode 100644 index 00000000..1a2c7b93 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/docker-compose.yaml @@ -0,0 +1,26 @@ +version: '3' +# Replace network name with the fabric test-network name +services: + redis: + image: 'redis' + ports: + - 6379:6379 + networks: + - net_test + + nodeapp: + image: 'fabricapp' + ports: + - 3000:3000 + env_file: + - ./.env + environment: + - REDIS_HOST=redis + - AS_LOCAL_HOST=false + networks: + - net_test + + +networks: + net_test: + external: true From b8509490ad26ff52f5dab6061b3e8bcc74395798 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Fri, 30 Jul 2021 14:19:10 +0530 Subject: [PATCH 071/106] retry count check build err fix retry condition testcase retryCount to maxRetryCount Signed-off-by: sapthasurendran --- .../scripts/generateEnv.sh | 2 + .../src/__mocks__/config.ts | 3 +- .../src/__mocks__/fabric-network.ts | 12 +++ .../src/__tests__/fabric.test.ts | 97 +++++++++++++++++++ .../rest-api-typescript/src/config.ts | 6 ++ .../rest-api-typescript/src/fabric.ts | 16 ++- .../rest-api-typescript/src/redis.ts | 17 ++++ 7 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index c0af2374..902397f8 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -21,6 +21,8 @@ PORT=3000 RETRY_DELAY=3000 +MAX_RETRY_COUNT=5 + HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .) HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts index b3a2bc44..42dddbab 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts @@ -7,6 +7,7 @@ export const logLevel = 'info'; export const port = '3000'; export const retryDelay = '3000'; +export const maxRetryCount = 5; export const asLocalHost = true; @@ -46,7 +47,7 @@ export const redisHost = 'localhost'; export const redisPort = '6379'; -export const redisUsername = 'conga'; +export const redisUsername = ''; export const redisPassword = ''; diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts index 216baff7..9ae7e06e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts @@ -32,10 +32,22 @@ mocked(Gateway.prototype.getNetwork).mockResolvedValue({ addBlockListener: jest.fn(), removeBlockListener: jest.fn(), }); +const getMockedNetwork = (getContract = jest.fn()) => { + return mocked(Gateway.prototype.getNetwork).mockResolvedValue({ + getGateway: jest.fn(), + getContract, + getChannel: jest.fn(), + addCommitListener: jest.fn(), + removeCommitListener: jest.fn(), + addBlockListener: jest.fn(), + removeBlockListener: jest.fn(), + }); +}; export { DefaultEventHandlerStrategies, DefaultQueryHandlerStrategies, Gateway, Wallets, + getMockedNetwork, }; diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts new file mode 100644 index 00000000..16ec024d --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts @@ -0,0 +1,97 @@ +import { retryTransaction } from '../fabric'; + +import { getMockedNetwork } from '../__mocks__/fabric-network'; +import { Redis } from 'ioredis'; +import * as redis from '../redis'; +// import { Gateway, Gateway, Gateway } from 'fabric-network'; + +/** + * retryTransaction + */ +jest.mock('../config'); + + +describe('Testing retryTransaction', () => { + let contract: any = null; + const transaction = { + submit: jest.fn().mockRejectedValue({}), + }; + const mockedContact = { + deserializeTransaction: jest.fn().mockReturnValue(transaction), + }; + beforeAll(async () => { + const rejectableGetContract = jest.fn().mockImplementation( + () => + mockedContact + ); + + const network = getMockedNetwork(rejectableGetContract)(''); + contract = (await network).getContract(''); + + }); + + describe('Check retry condition ', () => { + const transactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + const key = `txn:${transactionId}`; + const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; + const args = '["test111","red",400,"Jean",101]'; + const timestamp = 1628078044362; + const savedTransaction = { + timestamp: timestamp.toString(), + state: state, + retries: '', + args: args, + }; + + let data: Record = {}; + beforeEach(() => { + data = {}; + const clearTransactionDetails = jest.spyOn( + redis, + 'clearTransactionDetails' + ); + clearTransactionDetails.mockImplementation( + async (redis: Redis, transactionId: string) => { + const key = `txn:${transactionId}`; + delete data[key]; + } + ); + + const incrementRetryCount = jest.spyOn(redis, 'incrementRetryCount'); + incrementRetryCount.mockImplementation( + async (redis: Redis, transactionId: string) => { + const key = `txn:${transactionId}`; + data[key].retries = (parseInt(data[key].retries) + 1).toString(); + } + ); + }); + it('Transaction should exist if retry count is less then max rety count', async () => { + savedTransaction.retries = '3'; + data = { [key]: savedTransaction }; + await retryTransaction( + contract, + redis.redis, + transactionId, + savedTransaction + ); + expect(data[key]).toMatchObject({ + timestamp: timestamp.toString(), + state: state, + retries: '4', + args: args, + }); + }); + it('Clear transaction once retry reaches max retry count ', async () => { + savedTransaction.retries = '5'; + data = { [key]: savedTransaction }; + await retryTransaction( + contract, + redis.redis, + transactionId, + savedTransaction + ); + expect(data[key]).toBe(undefined); + }); + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index cc1b4216..375fc953 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -21,6 +21,12 @@ export const retryDelay = env .example('3000') .asIntPositive(); + export const maxRetryCount = env + .get('MAX_RETRY_COUNT') + .default('5') + .example('5') + .asIntPositive(); + export const asLocalHost = env .get('AS_LOCAL_HOST') .default('true') diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 4e642700..b28c6444 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -18,7 +18,11 @@ import { Request } from 'express'; import { Redis } from 'ioredis'; import * as config from './config'; import { logger } from './logger'; -import { storeTransactionDetails, clearTransactionDetails } from './redis'; +import { + storeTransactionDetails, + clearTransactionDetails, + incrementRetryCount, +} from './redis'; import { AssetExistsError, AssetNotFoundError, @@ -251,12 +255,12 @@ const handleError = (transactionId: string, err: Error): Error => { return new TransactionError('Transaction error', transactionId); }; -const retryTransaction = async ( +export const retryTransaction = async ( contract: Contract, redis: Redis, transactionId: string, savedTransaction: Record -) => { +): Promise => { logger.debug('Retrying transaction %s', transactionId); try { @@ -279,7 +283,11 @@ const retryTransaction = async ( savedTransaction.retries, transactionId ); - await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1); + if (parseInt(savedTransaction.retries) < config.maxRetryCount) { + await incrementRetryCount(redis, transactionId); + } else { + await clearTransactionDetails(redis, transactionId); + } } } }; diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.ts b/asset-transfer-basic/rest-api-typescript/src/redis.ts index d799d800..2077a68b 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.ts @@ -70,3 +70,20 @@ export const clearTransactionDetails = async ( }; // TODO add getTransaction etc. helpers? + +export const incrementRetryCount = async ( + redis: Redis, + transactionId: string +): Promise => { + const key = `txn:${transactionId}`; + logger.debug('Incrementing retries fortransaction Key: %s', key); + try { + await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1); + } catch (err) { + logger.error( + err, + 'Error incrementing retries for transaction ID %s', + transactionId + ); + } +}; From 5bea58e501a3c908bdc7c5a5a43018aeb25b1577 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Thu, 5 Aug 2021 17:12:14 +0530 Subject: [PATCH 072/106] retry condition moved to startretryloop Signed-off-by: sapthasurendran --- .../src/__tests__/fabric.test.ts | 24 ++++--------------- .../rest-api-typescript/src/config.ts | 2 +- .../rest-api-typescript/src/fabric.ts | 23 +++++++++--------- 3 files changed, 17 insertions(+), 32 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts index 16ec024d..ec2948b9 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts @@ -10,7 +10,6 @@ import * as redis from '../redis'; */ jest.mock('../config'); - describe('Testing retryTransaction', () => { let contract: any = null; const transaction = { @@ -20,17 +19,15 @@ describe('Testing retryTransaction', () => { deserializeTransaction: jest.fn().mockReturnValue(transaction), }; beforeAll(async () => { - const rejectableGetContract = jest.fn().mockImplementation( - () => - mockedContact - ); + const rejectableGetContract = jest + .fn() + .mockImplementation(() => mockedContact); const network = getMockedNetwork(rejectableGetContract)(''); contract = (await network).getContract(''); - }); - describe('Check retry condition ', () => { + describe('Check retry increment ', () => { const transactionId = '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; const key = `txn:${transactionId}`; @@ -66,7 +63,7 @@ describe('Testing retryTransaction', () => { } ); }); - it('Transaction should exist if retry count is less then max rety count', async () => { + it('retry count should incremnt to 4', async () => { savedTransaction.retries = '3'; data = { [key]: savedTransaction }; await retryTransaction( @@ -82,16 +79,5 @@ describe('Testing retryTransaction', () => { args: args, }); }); - it('Clear transaction once retry reaches max retry count ', async () => { - savedTransaction.retries = '5'; - data = { [key]: savedTransaction }; - await retryTransaction( - contract, - redis.redis, - transactionId, - savedTransaction - ); - expect(data[key]).toBe(undefined); - }); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 375fc953..019ab4dd 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -21,7 +21,7 @@ export const retryDelay = env .example('3000') .asIntPositive(); - export const maxRetryCount = env +export const maxRetryCount = env .get('MAX_RETRY_COUNT') .default('5') .example('5') diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index b28c6444..a9543190 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -136,13 +136,16 @@ export const startRetryLoop = (contract: Contract, redis: Redis): void => { const savedTransaction = await (redis as Redis).hgetall( `txn:${transactionId}` ); - - await retryTransaction( - contract, - redis, - transactionId, - savedTransaction - ); + if (parseInt(savedTransaction.retries) >= config.maxRetryCount) { + await clearTransactionDetails(redis, transactionId); + } else { + await retryTransaction( + contract, + redis, + transactionId, + savedTransaction + ); + } } } catch (err) { // TODO just log? @@ -283,11 +286,7 @@ export const retryTransaction = async ( savedTransaction.retries, transactionId ); - if (parseInt(savedTransaction.retries) < config.maxRetryCount) { - await incrementRetryCount(redis, transactionId); - } else { - await clearTransactionDetails(redis, transactionId); - } + await incrementRetryCount(redis, transactionId); } } }; From e81a7a8b4637e1b1d9f2a42c854fbf253a213f08 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 5 Aug 2021 12:39:24 +0100 Subject: [PATCH 073/106] Update port number config Discovered that env-var will validate port numbers, which is nice Signed-off-by: James Taylor --- asset-transfer-basic/rest-api-typescript/src/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 019ab4dd..31b5f96f 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -13,7 +13,7 @@ export const port = env .get('PORT') .default('3000') .example('3000') - .asIntPositive(); + .asPortNumber(); export const retryDelay = env .get('RETRY_DELAY') @@ -123,7 +123,7 @@ export const redisPort = env .get('REDIS_PORT') .default('6379') .example('6379') - .asIntPositive(); + .asPortNumber(); export const redisUsername = env .get('REDIS_USERNAME') From f904adbf6ff15ffaa45a735d01a7489abf266f8c Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 9 Aug 2021 16:13:51 +0100 Subject: [PATCH 074/106] Add config spec tests Signed-off-by: James Taylor --- .../rest-api-typescript/jest.config.ts | 16 + .../rest-api-typescript/package-lock.json | 6 +- .../rest-api-typescript/package.json | 2 +- .../src/__mocks__/config.ts | 56 --- .../src/__tests__/api.test.ts | 1 - .../rest-api-typescript/src/config.spec.ts | 465 ++++++++++++++++++ .../rest-api-typescript/src/config.ts | 86 +++- .../rest-api-typescript/src/fabric.ts | 4 +- 8 files changed, 572 insertions(+), 64 deletions(-) delete mode 100644 asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/config.spec.ts diff --git a/asset-transfer-basic/rest-api-typescript/jest.config.ts b/asset-transfer-basic/rest-api-typescript/jest.config.ts index ba3bbbc4..d11325d5 100644 --- a/asset-transfer-basic/rest-api-typescript/jest.config.ts +++ b/asset-transfer-basic/rest-api-typescript/jest.config.ts @@ -190,3 +190,19 @@ export default { // Whether to use watchman for file crawling // watchman: true, }; + +// Required environment variable values for the config.ts file +process.env = Object.assign(process.env, { + HLF_CONNECTION_PROFILE_ORG1: '{"name":"mock-profile-org1"}', + HLF_CERTIFICATE_ORG1: + '"-----BEGIN CERTIFICATE-----\\nMOCK\\n-----END CERTIFICATE-----\\n"', + HLF_PRIVATE_KEY_ORG1: + '"-----BEGIN PRIVATE KEY-----\\nMOCK\\n-----END PRIVATE KEY-----\\n"', + HLF_CONNECTION_PROFILE_ORG2: '{"name":"mock-profile-org2"}', + HLF_CERTIFICATE_ORG2: + '"-----BEGIN CERTIFICATE-----\\nMOCK\\n-----END CERTIFICATE-----\\n"', + HLF_PRIVATE_KEY_ORG2: + '"-----BEGIN PRIVATE KEY-----\\nMOCK\\n-----END PRIVATE KEY-----\\n"', + ORG1_APIKEY: 'ORG1MOCKAPIKEY', + ORG2_APIKEY: 'ORG2MOCKAPIKEY', +}); diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index 4270a380..3c44608f 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -1275,9 +1275,9 @@ "dev": true }, "@types/node": { - "version": "15.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz", - "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==" + "version": "15.14.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.7.tgz", + "integrity": "sha512-FA45p37/mLhpebgbPWWCKfOisTjxGK9lwcHlJ6XVLfu3NgfcazOJHdYUZCWPMK8QX4LhNZdmfo6iMz9FqpUbaw==" }, "@types/passport": { "version": "1.0.7", diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index 328e5f45..2f1e86fc 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -22,7 +22,7 @@ "@types/express": "^4.17.12", "@types/ioredis": "^4.26.4", "@types/jest": "^26.0.24", - "@types/node": "^15.12.4", + "@types/node": "^15.14.7", "@types/passport": "^1.0.7", "@types/pino": "^6.3.8", "@types/pino-http": "^5.4.1", diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts deleted file mode 100644 index 42dddbab..00000000 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/config.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -export const logLevel = 'info'; - -export const port = '3000'; - -export const retryDelay = '3000'; -export const maxRetryCount = 5; - -export const asLocalHost = true; - -export const identityNameOrg1 = 'Org1'; - -export const identityNameOrg2 = 'Org2'; - -export const mspIdOrg1 = 'Org1MSP'; - -export const mspIdOrg2 = 'Org2MSP'; - -export const channelName = 'mychannel'; - -export const chaincodeName = 'basic'; - -export const commitTimeout = '3000'; - -export const endorseTimeout = '30'; - -export const connectionProfileOrg1 = '{"name":"mock-profile-org1"}'; - -export const certificateOrg1 = - '"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"'; - -export const privateKeyOrg1 = - '"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"'; - -export const connectionProfileOrg2 = '{"name":"mock-profile-org2"}'; - -export const certificateOrg2 = - '"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"'; - -export const privateKeyOrg2 = - '"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"'; - -export const redisHost = 'localhost'; - -export const redisPort = '6379'; - -export const redisUsername = ''; - -export const redisPassword = ''; - -export const org1ApiKey = '123'; - -export const org2ApiKey = '456'; diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts index 5e0366b2..0da71ca3 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts @@ -6,7 +6,6 @@ import { createServer } from '../server'; import { Application } from 'express'; import request from 'supertest'; -jest.mock('../config'); jest.mock('fabric-network'); jest.mock('ioredis'); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.spec.ts b/asset-transfer-basic/rest-api-typescript/src/config.spec.ts new file mode 100644 index 00000000..cdfc6ecb --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/config.spec.ts @@ -0,0 +1,465 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +/* eslint-disable @typescript-eslint/no-var-requires */ + +describe('Config values', () => { + const ORIGINAL_ENV = process.env; + + beforeEach(async () => { + jest.resetModules(); + process.env = { ...ORIGINAL_ENV }; + }); + + afterAll(() => { + process.env = { ...ORIGINAL_ENV }; + }); + + describe('logLevel', () => { + it('defaults to "info"', () => { + const config = require('./config'); + expect(config.logLevel).toBe('info'); + }); + + it('can be configured using the "LOG_LEVEL" environment variable', () => { + process.env.LOG_LEVEL = 'debug'; + const config = require('./config'); + expect(config.logLevel).toBe('debug'); + }); + + it('throws an error when the "LOG_LEVEL" environment variable has an invalid log level', () => { + process.env.LOG_LEVEL = 'ludicrous'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "LOG_LEVEL" should be one of [fatal, error, warn, info, debug, trace, silent]' + ); + }); + }); + + describe('port', () => { + it('defaults to "3000"', () => { + const config = require('./config'); + expect(config.port).toBe(3000); + }); + + it('can be configured using the "PORT" environment variable', () => { + process.env.PORT = '8000'; + const config = require('./config'); + expect(config.port).toBe(8000); + }); + + it('throws an error when the "PORT" environment variable has an invalid port number', () => { + process.env.PORT = '65536'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "PORT" cannot assign a port number greater than 65535. An example of a valid value would be: 3000' + ); + }); + }); + + describe('retryDelay', () => { + it('defaults to "3000"', () => { + const config = require('./config'); + expect(config.retryDelay).toBe(3000); + }); + + it('can be configured using the "RETRY_DELAY" environment variable', () => { + process.env.RETRY_DELAY = '9999'; + const config = require('./config'); + expect(config.retryDelay).toBe(9999); + }); + + it('throws an error when the "RETRY_DELAY" environment variable has an invalid number', () => { + process.env.RETRY_DELAY = 'short'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "RETRY_DELAY" should be a valid integer. An example of a valid value would be: 3000' + ); + }); + }); + + describe('maxRetryCount', () => { + it('defaults to "5"', () => { + const config = require('./config'); + expect(config.maxRetryCount).toBe(5); + }); + + it('can be configured using the "MAX_RETRY_COUNT" environment variable', () => { + process.env.MAX_RETRY_COUNT = '9999'; + const config = require('./config'); + expect(config.maxRetryCount).toBe(9999); + }); + + it('throws an error when the "MAX_RETRY_COUNT" environment variable has an invalid number', () => { + process.env.MAX_RETRY_COUNT = 'lots'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "MAX_RETRY_COUNT" should be a valid integer. An example of a valid value would be: 5' + ); + }); + }); + + describe('asLocalhost', () => { + it('defaults to "true"', () => { + const config = require('./config'); + expect(config.asLocalhost).toBe(true); + }); + + it('can be configured using the "AS_LOCAL_HOST" environment variable', () => { + process.env.AS_LOCAL_HOST = 'false'; + const config = require('./config'); + expect(config.asLocalhost).toBe(false); + }); + + it('throws an error when the "AS_LOCAL_HOST" environment variable has an invalid boolean value', () => { + process.env.AS_LOCAL_HOST = '11'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "AS_LOCAL_HOST" should be either "true", "false", "TRUE", or "FALSE". An example of a valid value would be: true' + ); + }); + }); + + describe('mspIdOrg1', () => { + it('defaults to "Org1MSP"', () => { + const config = require('./config'); + expect(config.mspIdOrg1).toBe('Org1MSP'); + }); + + it('can be configured using the "HLF_MSP_ID_ORG1" environment variable', () => { + process.env.HLF_MSP_ID_ORG1 = 'Test1MSP'; + const config = require('./config'); + expect(config.mspIdOrg1).toBe('Test1MSP'); + }); + }); + + describe('mspIdOrg2', () => { + it('defaults to "Org2MSP"', () => { + const config = require('./config'); + expect(config.mspIdOrg2).toBe('Org2MSP'); + }); + + it('can be configured using the "HLF_MSP_ID_ORG2" environment variable', () => { + process.env.HLF_MSP_ID_ORG2 = 'Test2MSP'; + const config = require('./config'); + expect(config.mspIdOrg2).toBe('Test2MSP'); + }); + }); + + describe('channelName', () => { + it('defaults to "mychannel"', () => { + const config = require('./config'); + expect(config.channelName).toBe('mychannel'); + }); + + it('can be configured using the "HLF_CHANNEL_NAME" environment variable', () => { + process.env.HLF_CHANNEL_NAME = 'testchannel'; + const config = require('./config'); + expect(config.channelName).toBe('testchannel'); + }); + }); + + describe('chaincodeName', () => { + it('defaults to "basic"', () => { + const config = require('./config'); + expect(config.chaincodeName).toBe('basic'); + }); + + it('can be configured using the "HLF_CHAINCODE_NAME" environment variable', () => { + process.env.HLF_CHAINCODE_NAME = 'testcc'; + const config = require('./config'); + expect(config.chaincodeName).toBe('testcc'); + }); + }); + + describe('commitTimeout', () => { + it('defaults to "3000"', () => { + const config = require('./config'); + expect(config.commitTimeout).toBe(3000); + }); + + it('can be configured using the "HLF_COMMIT_TIMEOUT" environment variable', () => { + process.env.HLF_COMMIT_TIMEOUT = '9999'; + const config = require('./config'); + expect(config.commitTimeout).toBe(9999); + }); + + it('throws an error when the "HLF_COMMIT_TIMEOUT" environment variable has an invalid number', () => { + process.env.HLF_COMMIT_TIMEOUT = 'short'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_COMMIT_TIMEOUT" should be a valid integer. An example of a valid value would be: 3000' + ); + }); + }); + + describe('endorseTimeout', () => { + it('defaults to "30"', () => { + const config = require('./config'); + expect(config.endorseTimeout).toBe(30); + }); + + it('can be configured using the "HLF_ENDORSE_TIMEOUT" environment variable', () => { + process.env.HLF_ENDORSE_TIMEOUT = '9999'; + const config = require('./config'); + expect(config.endorseTimeout).toBe(9999); + }); + + it('throws an error when the "HLF_ENDORSE_TIMEOUT" environment variable has an invalid number', () => { + process.env.HLF_ENDORSE_TIMEOUT = 'short'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_ENDORSE_TIMEOUT" should be a valid integer. An example of a valid value would be: 30' + ); + }); + }); + + describe('queryTimeout', () => { + it('defaults to "3"', () => { + const config = require('./config'); + expect(config.queryTimeout).toBe(3); + }); + + it('can be configured using the "HLF_QUERY_TIMEOUT" environment variable', () => { + process.env.HLF_QUERY_TIMEOUT = '9999'; + const config = require('./config'); + expect(config.queryTimeout).toBe(9999); + }); + + it('throws an error when the "HLF_QUERY_TIMEOUT" environment variable has an invalid number', () => { + process.env.HLF_QUERY_TIMEOUT = 'long'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_QUERY_TIMEOUT" should be a valid integer. An example of a valid value would be: 3' + ); + }); + }); + + describe('connectionProfileOrg1', () => { + it('throws an error when the "HLF_CONNECTION_PROFILE_ORG1" environment variable is not set', () => { + delete process.env.HLF_CONNECTION_PROFILE_ORG1; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_CONNECTION_PROFILE_ORG1" is a required variable, but it was not set. An example of a valid value would be: {"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... }' + ); + }); + + it('can be configured using the "HLF_CONNECTION_PROFILE_ORG1" environment variable', () => { + process.env.HLF_CONNECTION_PROFILE_ORG1 = '{"name":"test-network-org1"}'; + const config = require('./config'); + expect(config.connectionProfileOrg1).toStrictEqual({ + name: 'test-network-org1', + }); + }); + + it('throws an error when the "HLF_CONNECTION_PROFILE_ORG1" environment variable is set to invalid json', () => { + process.env.HLF_CONNECTION_PROFILE_ORG1 = 'testing'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_CONNECTION_PROFILE_ORG1" should be valid (parseable) JSON. An example of a valid value would be: {"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... }' + ); + }); + }); + + describe('certificateOrg1', () => { + it('throws an error when the "HLF_CERTIFICATE_ORG1" environment variable is not set', () => { + delete process.env.HLF_CERTIFICATE_ORG1; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_CERTIFICATE_ORG1" is a required variable, but it was not set. An example of a valid value would be: "-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"' + ); + }); + + it('can be configured using the "HLF_CERTIFICATE_ORG1" environment variable', () => { + process.env.HLF_CERTIFICATE_ORG1 = 'ORG1CERT'; + const config = require('./config'); + expect(config.certificateOrg1).toBe('ORG1CERT'); + }); + }); + + describe('privateKeyOrg1', () => { + it('throws an error when the "HLF_PRIVATE_KEY_ORG1" environment variable is not set', () => { + delete process.env.HLF_PRIVATE_KEY_ORG1; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_PRIVATE_KEY_ORG1" is a required variable, but it was not set. An example of a valid value would be: "-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"' + ); + }); + + it('can be configured using the "HLF_PRIVATE_KEY_ORG1" environment variable', () => { + process.env.HLF_PRIVATE_KEY_ORG1 = 'ORG1PK'; + const config = require('./config'); + expect(config.privateKeyOrg1).toBe('ORG1PK'); + }); + }); + + describe('connectionProfileOrg2', () => { + it('throws an error when the "HLF_CONNECTION_PROFILE_ORG2" environment variable is not set', () => { + delete process.env.HLF_CONNECTION_PROFILE_ORG2; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_CONNECTION_PROFILE_ORG2" is a required variable, but it was not set. An example of a valid value would be: {"name":"test-network-org2","version":"1.0.0","client":{"organization":"Org2" ... }' + ); + }); + + it('can be configured using the "HLF_CONNECTION_PROFILE_ORG2" environment variable', () => { + process.env.HLF_CONNECTION_PROFILE_ORG2 = '{"name":"test-network-org2"}'; + const config = require('./config'); + expect(config.connectionProfileOrg2).toStrictEqual({ + name: 'test-network-org2', + }); + }); + + it('throws an error when the "HLF_CONNECTION_PROFILE_ORG2" environment variable is set to invalid json', () => { + process.env.HLF_CONNECTION_PROFILE_ORG2 = 'testing'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_CONNECTION_PROFILE_ORG2" should be valid (parseable) JSON. An example of a valid value would be: {"name":"test-network-org2","version":"1.0.0","client":{"organization":"Org2" ... }' + ); + }); + }); + + describe('certificateOrg2', () => { + it('throws an error when the "HLF_CERTIFICATE_ORG2" environment variable is not set', () => { + delete process.env.HLF_CERTIFICATE_ORG2; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_CERTIFICATE_ORG2" is a required variable, but it was not set. An example of a valid value would be: "-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"' + ); + }); + + it('can be configured using the "HLF_CERTIFICATE_ORG2" environment variable', () => { + process.env.HLF_CERTIFICATE_ORG2 = 'ORG2CERT'; + const config = require('./config'); + expect(config.certificateOrg2).toBe('ORG2CERT'); + }); + }); + + describe('privateKeyOrg2', () => { + it('throws an error when the "HLF_PRIVATE_KEY_ORG2" environment variable is not set', () => { + delete process.env.HLF_PRIVATE_KEY_ORG2; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_PRIVATE_KEY_ORG2" is a required variable, but it was not set. An example of a valid value would be: "-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"' + ); + }); + + it('can be configured using the "HLF_PRIVATE_KEY_ORG2" environment variable', () => { + process.env.HLF_PRIVATE_KEY_ORG2 = 'ORG2PK'; + const config = require('./config'); + expect(config.privateKeyOrg2).toBe('ORG2PK'); + }); + }); + + describe('redisHost', () => { + it('defaults to "localhost"', () => { + const config = require('./config'); + expect(config.redisHost).toBe('localhost'); + }); + + it('can be configured using the "REDIS_HOST" environment variable', () => { + process.env.REDIS_HOST = 'redis.example.org'; + const config = require('./config'); + expect(config.redisHost).toBe('redis.example.org'); + }); + }); + + describe('redisPort', () => { + it('defaults to "6379"', () => { + const config = require('./config'); + expect(config.redisPort).toBe(6379); + }); + + it('can be configured with a valid port number using the "REDIS_PORT" environment variable', () => { + process.env.REDIS_PORT = '9736'; + const config = require('./config'); + expect(config.redisPort).toBe(9736); + }); + + it('throws an error when the "REDIS_PORT" environment variable has an invalid port number', () => { + process.env.REDIS_PORT = '65536'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "REDIS_PORT" cannot assign a port number greater than 65535. An example of a valid value would be: 6379' + ); + }); + }); + + describe('redisUsername', () => { + it('has no default value', () => { + const config = require('./config'); + expect(config.redisUsername).toBeUndefined(); + }); + + it('can be configured using the "REDIS_USERNAME" environment variable', () => { + process.env.REDIS_USERNAME = 'test'; + const config = require('./config'); + expect(config.redisUsername).toBe('test'); + }); + }); + + describe('redisPassword', () => { + it('has no default value', () => { + const config = require('./config'); + expect(config.redisPassword).toBeUndefined(); + }); + + it('can be configured using the "REDIS_PASSWORD" environment variable', () => { + process.env.REDIS_PASSWORD = 'testpw'; + const config = require('./config'); + expect(config.redisPassword).toBe('testpw'); + }); + }); + + describe('org1ApiKey', () => { + it('throws an error when the "ORG1_APIKEY" environment variable is not set', () => { + delete process.env.ORG1_APIKEY; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "ORG1_APIKEY" is a required variable, but it was not set. An example of a valid value would be: 123' + ); + }); + + it('can be configured using the "ORG1_APIKEY" environment variable', () => { + process.env.ORG1_APIKEY = 'org1ApiKey'; + const config = require('./config'); + expect(config.org1ApiKey).toBe('org1ApiKey'); + }); + }); + + describe('org2ApiKey', () => { + it('throws an error when the "ORG1_APIKEY" environment variable is not set', () => { + delete process.env.ORG2_APIKEY; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "ORG2_APIKEY" is a required variable, but it was not set. An example of a valid value would be: 456' + ); + }); + + it('can be configured using the "ORG1_APIKEY" environment variable', () => { + process.env.ORG2_APIKEY = 'org2ApiKey'; + const config = require('./config'); + expect(config.org2ApiKey).toBe('org2ApiKey'); + }); + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 31b5f96f..3a00c813 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -4,75 +4,124 @@ import * as env from 'env-var'; +/* + * Log level for the REST server + */ export const logLevel = env .get('LOG_LEVEL') .default('info') .asEnum(['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent']); +/* + * The port to start the REST server on + */ export const port = env .get('PORT') .default('3000') .example('3000') .asPortNumber(); +/* + * The delay between each retry attempt in milliseconds + */ export const retryDelay = env .get('RETRY_DELAY') .default('3000') .example('3000') .asIntPositive(); +/* + * The maximum number of times to retry a failing transaction + */ export const maxRetryCount = env .get('MAX_RETRY_COUNT') .default('5') .example('5') .asIntPositive(); -export const asLocalHost = env +/* + * Whether to convert discovered host addresses to be 'localhost' + * This should be set to 'true' when running a docker composed fabric network on the + * local system, e.g. using the test network; otherwise should it should be 'false' + */ +export const asLocalhost = env .get('AS_LOCAL_HOST') .default('true') .example('true') .asBoolStrict(); +// TODO delete this and use mspIdOrg1 export const identityNameOrg1 = 'Org1'; +// TODO delete this and use mspIdOrg2 export const identityNameOrg2 = 'Org2'; +/* + * The Org1 MSP ID + */ export const mspIdOrg1 = env .get('HLF_MSP_ID_ORG1') .default('Org1MSP') .example('Org1MSP') .asString(); +/* + * The Org2 MSP ID + */ export const mspIdOrg2 = env .get('HLF_MSP_ID_ORG2') .default('Org2MSP') .example('Org2MSP') .asString(); +/* + * Name of the channel which the basic asset sample chaincode has been installed on + */ export const channelName = env .get('HLF_CHANNEL_NAME') .default('mychannel') .example('mychannel') .asString(); +/* + * Name used to install the basic asset sample + */ export const chaincodeName = env .get('HLF_CHAINCODE_NAME') .default('basic') .example('basic') .asString(); +/* + * The transaction submit timeout in seconds for commit notification to complete + */ export const commitTimeout = env .get('HLF_COMMIT_TIMEOUT') .default('3000') .example('3000') .asIntPositive(); +/* + * The transaction submit timeout in seconds for the endorsement to complete + */ export const endorseTimeout = env .get('HLF_ENDORSE_TIMEOUT') .default('30') .example('30') .asIntPositive(); +/* + * The transaction query timeout in seconds + */ +export const queryTimeout = env + .get('HLF_QUERY_TIMEOUT') + .default('3') + .example('3') + .asIntPositive(); + +/* + * The Org1 connection profile JSON + */ export const connectionProfileOrg1 = env .get('HLF_CONNECTION_PROFILE_ORG1') .required() @@ -81,18 +130,27 @@ export const connectionProfileOrg1 = env ) .asJsonObject(); +/* + * Certificate for the Org1 identity + */ export const certificateOrg1 = env .get('HLF_CERTIFICATE_ORG1') .required() .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') .asString(); +/* + * Private key for the Org1 identity + */ export const privateKeyOrg1 = env .get('HLF_PRIVATE_KEY_ORG1') .required() .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') .asString(); +/* + * The Org2 connection profile JSON + */ export const connectionProfileOrg2 = env .get('HLF_CONNECTION_PROFILE_ORG2') .required() @@ -101,43 +159,69 @@ export const connectionProfileOrg2 = env ) .asJsonObject(); +/* + * Certificate for the Org2 identity + */ export const certificateOrg2 = env .get('HLF_CERTIFICATE_ORG2') .required() .example('"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"') .asString(); +/* + * Private key for the Org2 identity + */ export const privateKeyOrg2 = env .get('HLF_PRIVATE_KEY_ORG2') .required() .example('"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"') .asString(); +/* + * The host the Redis server is running on + */ export const redisHost = env .get('REDIS_HOST') .default('localhost') .example('localhost') .asString(); +/* + * The port the Redis server is running on + */ export const redisPort = env .get('REDIS_PORT') .default('6379') .example('6379') .asPortNumber(); +/* + * Username for the Redis server + */ export const redisUsername = env .get('REDIS_USERNAME') .example('conga') .asString(); +/* + * Password for the Redis server + */ export const redisPassword = env.get('REDIS_PASSWORD').asString(); +/* + * API key for Org1 + * Specify this API key with the X-Api-Key header to use the Org1 connection profile and credentials + */ export const org1ApiKey = env .get('ORG1_APIKEY') .required() .example('123') .asString(); +/* + * API key for Org2 + * Specify this API key with the X-Api-Key header to use the Org2 connection profile and credentials + */ export const org2ApiKey = env .get('ORG2_APIKEY') .required() diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index a9543190..b7bee9a3 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -85,14 +85,14 @@ export const getGateway = async (org: string): Promise => { const connectOptions: GatewayOptions = { wallet, identity: fabricConfig.identityName, - discovery: { enabled: true, asLocalhost: config.asLocalHost }, + discovery: { enabled: true, asLocalhost: config.asLocalhost }, eventHandlerOptions: { commitTimeout: config.commitTimeout, endorseTimeout: config.endorseTimeout, strategy: DefaultEventHandlerStrategies.PREFER_MSPID_SCOPE_ANYFORTX, }, queryHandlerOptions: { - timeout: 3, + timeout: config.queryTimeout, strategy: DefaultQueryHandlerStrategies.PREFER_MSPID_SCOPE_ROUND_ROBIN, }, }; From 6477333743a8fc199918e05a453533fa846e441d Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Mon, 9 Aug 2021 11:38:21 +0530 Subject: [PATCH 075/106] redis mock class code cleanup created fabric.spec redis testcases and additional checks Signed-off-by: sapthasurendran --- .../rest-api-typescript/package-lock.json | 6 +- .../src/__mocks__/IORedis.ts | 21 +++++ .../src/__tests__/fabric.test.ts | 83 ---------------- .../rest-api-typescript/src/fabric.spec.ts | 94 +++++++++++++++++++ .../rest-api-typescript/src/fabric.ts | 5 +- .../rest-api-typescript/src/redis.spec.ts | 75 +++++++++++++++ .../rest-api-typescript/src/redis.ts | 54 +++++++---- 7 files changed, 231 insertions(+), 107 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/__mocks__/IORedis.ts delete mode 100644 asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/redis.spec.ts diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index 3c44608f..99399c39 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -1215,9 +1215,9 @@ } }, "@types/ioredis": { - "version": "4.26.4", - "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.26.4.tgz", - "integrity": "sha512-QFbjNq7EnOGw6d1gZZt2h26OFXjx7z+eqEnbCHSrDI1OOLEgOHMKdtIajJbuCr9uO+X9kQQRe7Lz6uxqxl5XKg==", + "version": "4.26.6", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.26.6.tgz", + "integrity": "sha512-Q9ydXL/5Mot751i7WLCm9OGTj5jlW3XBdkdEW21SkXZ8Y03srbkluFGbM3q8c+vzPW30JOLJ+NsZWHoly0+13A==", "dev": true, "requires": { "@types/node": "*" diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/IORedis.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/IORedis.ts new file mode 100644 index 00000000..bc31167e --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/IORedis.ts @@ -0,0 +1,21 @@ +import { RedisOptions } from 'ioredis'; + +class IORedis { + redisOptions: RedisOptions; + constructor(options: RedisOptions) { + this.redisOptions = options; + } + + hincrby = jest.fn().mockReturnThis(); + multi = jest.fn().mockReturnThis(); + del = jest.fn().mockReturnThis(); + + zrem = jest.fn().mockReturnThis(); + + exec = jest.fn().mockReturnThis(); + + hset = jest.fn().mockReturnThis(); + zadd = jest.fn().mockReturnThis(); +} + +export default IORedis; diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts deleted file mode 100644 index ec2948b9..00000000 --- a/asset-transfer-basic/rest-api-typescript/src/__tests__/fabric.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { retryTransaction } from '../fabric'; - -import { getMockedNetwork } from '../__mocks__/fabric-network'; -import { Redis } from 'ioredis'; -import * as redis from '../redis'; -// import { Gateway, Gateway, Gateway } from 'fabric-network'; - -/** - * retryTransaction - */ -jest.mock('../config'); - -describe('Testing retryTransaction', () => { - let contract: any = null; - const transaction = { - submit: jest.fn().mockRejectedValue({}), - }; - const mockedContact = { - deserializeTransaction: jest.fn().mockReturnValue(transaction), - }; - beforeAll(async () => { - const rejectableGetContract = jest - .fn() - .mockImplementation(() => mockedContact); - - const network = getMockedNetwork(rejectableGetContract)(''); - contract = (await network).getContract(''); - }); - - describe('Check retry increment ', () => { - const transactionId = - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - const key = `txn:${transactionId}`; - const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; - const args = '["test111","red",400,"Jean",101]'; - const timestamp = 1628078044362; - const savedTransaction = { - timestamp: timestamp.toString(), - state: state, - retries: '', - args: args, - }; - - let data: Record = {}; - beforeEach(() => { - data = {}; - const clearTransactionDetails = jest.spyOn( - redis, - 'clearTransactionDetails' - ); - clearTransactionDetails.mockImplementation( - async (redis: Redis, transactionId: string) => { - const key = `txn:${transactionId}`; - delete data[key]; - } - ); - - const incrementRetryCount = jest.spyOn(redis, 'incrementRetryCount'); - incrementRetryCount.mockImplementation( - async (redis: Redis, transactionId: string) => { - const key = `txn:${transactionId}`; - data[key].retries = (parseInt(data[key].retries) + 1).toString(); - } - ); - }); - it('retry count should incremnt to 4', async () => { - savedTransaction.retries = '3'; - data = { [key]: savedTransaction }; - await retryTransaction( - contract, - redis.redis, - transactionId, - savedTransaction - ); - expect(data[key]).toMatchObject({ - timestamp: timestamp.toString(), - state: state, - retries: '4', - args: args, - }); - }); - }); -}); diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts new file mode 100644 index 00000000..3cc7b1d8 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -0,0 +1,94 @@ +import { retryTransaction, getGateway } from './fabric'; +import { getMockedNetwork } from './__mocks__/fabric-network'; +import * as config from './config'; + +import IORedis from './__mocks__/IORedis'; +import { Redis } from 'ioredis'; +import { Contract } from 'fabric-network'; + +jest.mock('./config'); +jest.mock('ioredis'); +const redisOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, +}; + +const redis = new IORedis(redisOptions) as unknown as Redis; + +describe('Testing retryTransaction', () => { + const transactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; + const args = '["test111","red",400,"Jean",101]'; + const timestamp = 1628078044362; + const savedTransaction = { + timestamp: timestamp.toString(), + state: state, + retries: '', + args: args, + }; + + describe('Check retry increment ', () => { + const transactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; + const args = '["test111","red",400,"Jean",101]'; + const timestamp = 1628078044362; + const savedTransaction = { + timestamp: timestamp.toString(), + state: state, + retries: '', + args: args, + }; + + it('Transaction failure, check redis increment func call', async () => { + jest.doMock('fabric-network'); + const transaction = { + submit: jest.fn().mockRejectedValue({}), + }; + const mockedContact = { + deserializeTransaction: jest.fn().mockReturnValue(transaction), + }; + const rejectableGetContract = jest + .fn() + .mockImplementation(() => mockedContact); + + const network = getMockedNetwork(rejectableGetContract)(''); + const contract: Contract = (await network).getContract(''); + savedTransaction.retries = '3'; + await retryTransaction(contract, redis, transactionId, savedTransaction); + expect(redis.hincrby).toHaveBeenCalledTimes(1); + }); + }); + + describe('Transaction successful, check redis delete key func call ', () => { + it('call redis increment', async () => { + jest.doMock('fabric-network'); + const transaction = { + submit: jest.fn().mockResolvedValue({}), + }; + const mockedContact = { + deserializeTransaction: jest.fn().mockReturnValue(transaction), + }; + const resolvableGetContract = jest + .fn() + .mockImplementation(() => mockedContact); + + const network = getMockedNetwork(resolvableGetContract)(''); + const contract: Contract = (await network).getContract(''); + savedTransaction.retries = '3'; + await retryTransaction(contract, redis, transactionId, savedTransaction); + expect(redis.del).toHaveBeenCalledTimes(1); + }); + }); +}); + +describe('Test getGateway', () => { + it('should throw error for invalid org name', async () => { + expect(async () => await getGateway('')).rejects.toThrow( + 'Invalid org name for gateway' + ); + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index b7bee9a3..8af4fefe 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -67,6 +67,9 @@ const FabricDataMapper: { [key: string]: FabricConfigType } = { export const getGateway = async (org: string): Promise => { const fabricConfig = FabricDataMapper[org]; + if (fabricConfig == undefined) { + throw new Error('Invalid org name for gateway'); + } logger.debug('Configuring fabric gateway for %s', org); const wallet = await Wallets.newInMemoryWallet(); @@ -78,8 +81,8 @@ export const getGateway = async (org: string): Promise => { mspId: fabricConfig.mspId, type: 'X.509', }; - await wallet.put(fabricConfig.identityName, x509Identity); + await wallet.put(fabricConfig.identityName, x509Identity); const gateway = new Gateway(); const connectOptions: GatewayOptions = { diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts b/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts new file mode 100644 index 00000000..7d81cb99 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts @@ -0,0 +1,75 @@ +import IORedis from './__mocks__/IORedis'; +import * as config from './config'; +import { Redis } from 'ioredis'; +import { + clearTransactionDetails, + incrementRetryCount, + storeTransactionDetails, +} from './redis'; + +jest.mock('ioredis'); +jest.mock('./config'); + +const redisOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, +}; +const redis = new IORedis(redisOptions) as unknown as Redis; +describe('Testing increment retries ', () => { + const transactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + it('Should increment retries for valid transction id', async () => { + await incrementRetryCount(redis, transactionId); + expect(redis.hincrby).toHaveBeenCalledTimes(1); + }); + + it('Should not increment retries for empty transaction id ', async () => { + await incrementRetryCount(redis, ''); + expect(redis.hincrby).toHaveBeenCalledTimes(0); + }); +}); + +describe('Testing storeTransactionDetails ', () => { + const args = '["test111","red",400,"Jean",101]'; + const timestamp = 1628078044362; + it('Should store details for valid transction Id', async () => { + const transactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; + await storeTransactionDetails( + redis, + transactionId, + Buffer.from(state), + args, + timestamp + ); + expect(redis.hset).toHaveBeenCalledTimes(1); + expect(redis.zadd).toHaveBeenCalledTimes(1); + }); + + it('Should not store details for empty transction Id', async () => { + const transactionId = ''; + const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; + await storeTransactionDetails( + redis, + transactionId, + Buffer.from(state), + args, + timestamp + ); + expect(redis.hset).toHaveBeenCalledTimes(0); + expect(redis.zadd).toHaveBeenCalledTimes(0); + }); +}); + +describe('Testing clearTransactionDetails ', () => { + it('Should clear details ', async () => { + const transactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + await clearTransactionDetails(redis, transactionId); + expect(redis.del).toHaveBeenCalledTimes(1); + expect(redis.zrem).toHaveBeenCalledTimes(1); + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.ts b/asset-transfer-basic/rest-api-typescript/src/redis.ts index 2077a68b..c4e8b7c3 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.ts @@ -23,29 +23,40 @@ export const storeTransactionDetails = async ( transactionArgs: string, timestamp: number ): Promise => { - const key = `txn:${transactionId}`; - logger.debug( - 'Storing transaction details. Key: %s State: %s Args: %s Timestamp: %d', - key, - transactionState, - transactionArgs, - timestamp - ); - await redis - .multi() - .hset( + try { + if (transactionId.length === 0) { + throw new Error('Empty transaction Id found'); + } + const key = `txn:${transactionId}`; + logger.debug( + 'Storing transaction details. Key: %s State: %s Args: %s Timestamp: %d', key, - 'state', transactionState, - 'args', transactionArgs, - 'timestamp', - timestamp, - 'retries', - '0' - ) - .zadd('index:txn:timestamp', timestamp, transactionId) - .exec(); + timestamp + ); + await redis + .multi() + .hset( + key, + 'state', + transactionState, + 'args', + transactionArgs, + 'timestamp', + timestamp, + 'retries', + '0' + ) + .zadd('index:txn:timestamp', timestamp, transactionId) + .exec(); + } catch (err) { + logger.error( + err, + 'Error storing transaction details. ID %s', + transactionId + ); + } }; export const clearTransactionDetails = async ( @@ -78,6 +89,9 @@ export const incrementRetryCount = async ( const key = `txn:${transactionId}`; logger.debug('Incrementing retries fortransaction Key: %s', key); try { + if (transactionId.length === 0) { + throw new Error('Empty transaction Id found'); + } await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1); } catch (err) { logger.error( From 862080773e8a87ffbd686f0136298645e88c6d15 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 2 Aug 2021 14:09:11 +0100 Subject: [PATCH 076/106] Initial API tests Signed-off-by: James Taylor --- .../rest-api-typescript/package-lock.json | 73 +++ .../rest-api-typescript/package.json | 2 + .../src/__mocks__/fabric-network.ts | 171 ++++- .../src/__tests__/api.test.ts | 592 +++++++++++++++++- .../rest-api-typescript/src/assets.router.ts | 5 +- .../rest-api-typescript/src/fabric.ts | 8 +- 6 files changed, 826 insertions(+), 25 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index 99399c39..e7e35369 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -2934,6 +2934,31 @@ "bser": "2.1.1" } }, + "fengari": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/fengari/-/fengari-0.1.4.tgz", + "integrity": "sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g==", + "dev": true, + "requires": { + "readline-sync": "^1.4.9", + "sprintf-js": "^1.1.1", + "tmp": "^0.0.33" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, + "fengari-interop": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/fengari-interop/-/fengari-interop-0.1.2.tgz", + "integrity": "sha512-8iTvaByZVoi+lQJhHH9vC+c/Yaok9CwOqNQZN6JrVpjmWwW4dDkeblBXhnHC+BoI6eF4Cy5NKW3z6ICEjvgywQ==", + "dev": true + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3366,6 +3391,18 @@ } } }, + "ioredis-mock": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/ioredis-mock/-/ioredis-mock-5.6.0.tgz", + "integrity": "sha512-Ow+tyKdijg/gA2gSEv7lq8dLp6bO7FnwDXbJ9as37NF23XNRGMLzBc7ITaqMydfrbTodWnLcE2lKEaBs7SBpyA==", + "dev": true, + "requires": { + "fengari": "^0.1.4", + "fengari-interop": "^0.1.2", + "lodash": "^4.17.21", + "standard-as-callback": "^2.1.0" + } + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4299,6 +4336,15 @@ } } }, + "jest-mock-extended": { + "version": "2.0.2-beta2", + "resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-2.0.2-beta2.tgz", + "integrity": "sha512-56zcpgRPs3YxQP0ejcaaNFxUinPyRxQCbuk7GGORZqEbAFuQVXWAAtru2tI1N4qcLBoDWEJ/hwUxwbEGY5hdyw==", + "dev": true, + "requires": { + "ts-essentials": "^7.0.3" + } + }, "jest-pnp-resolver": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", @@ -5246,6 +5292,12 @@ "word-wrap": "^1.2.3" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, "p-each-series": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", @@ -5636,6 +5688,12 @@ "util-deprecate": "^1.0.1" } }, + "readline-sync": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", + "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", + "dev": true + }, "redis-commands": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", @@ -6198,6 +6256,15 @@ "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", @@ -6258,6 +6325,12 @@ } } }, + "ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true + }, "ts-jest": { "version": "27.0.4", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.4.tgz", diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index 2f1e86fc..18919584 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -32,7 +32,9 @@ "eslint": "^7.29.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^3.4.0", + "ioredis-mock": "^5.6.0", "jest": "^27.0.6", + "jest-mock-extended": "^2.0.2-beta2", "pino-pretty": "^5.0.2", "prettier": "^2.3.1", "rimraf": "^3.0.2", diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts index 9ae7e06e..d13ff057 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts @@ -2,7 +2,47 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { mock } from 'jest-mock-extended'; +import { Contract, Network, Transaction, WalletStore } from 'fabric-network'; import { mocked } from 'ts-jest/utils'; +import * as fabricProtos from 'fabric-protos'; + +const mockAsset1 = { + ID: 'asset1', + Color: 'blue', + Size: 5, + Owner: 'Tomoko', + AppraisedValue: 300, +}; +const mockAsset1Buffer = Buffer.from(JSON.stringify(mockAsset1)); + +const mockAsset2 = { + ID: 'asset2', + Color: 'red', + Size: 5, + Owner: 'Brad', + AppraisedValue: 400, +}; + +const mockAllAssetsBuffer = Buffer.from( + JSON.stringify([mockAsset1, mockAsset2]) +); + +const mockBlockchainInfoProto = fabricProtos.common.BlockchainInfo.create(); +mockBlockchainInfoProto.height = 42; +const mockBlockchainInfoBuffer = Buffer.from( + fabricProtos.common.BlockchainInfo.encode(mockBlockchainInfoProto).finish() +); + +const processedTransactionProto = + fabricProtos.protos.ProcessedTransaction.create(); +processedTransactionProto.validationCode = + fabricProtos.protos.TxValidationCode.VALID; +const processedTransactionBuffer = Buffer.from( + fabricProtos.protos.ProcessedTransaction.encode( + processedTransactionProto + ).finish() +); type FabricNetworkModule = jest.Mocked; @@ -14,24 +54,124 @@ const { Wallets, }: FabricNetworkModule = jest.createMockFromModule('fabric-network'); +const mockWalletStore = mock(); mocked(Wallets.newInMemoryWallet).mockResolvedValue( - new Wallet({ - get: jest.fn(), - list: jest.fn(), - put: jest.fn(), - remove: jest.fn(), - }) + new Wallet(mockWalletStore) ); -mocked(Gateway.prototype.getNetwork).mockResolvedValue({ - getGateway: jest.fn(), - getContract: jest.fn(), - getChannel: jest.fn(), - addCommitListener: jest.fn(), - removeCommitListener: jest.fn(), - addBlockListener: jest.fn(), - removeBlockListener: jest.fn(), -}); +const mockAssetExistsTransaction = mock(); +mockAssetExistsTransaction.evaluate + .calledWith('asset1') + .mockResolvedValue(Buffer.from('true')); +mockAssetExistsTransaction.evaluate + .calledWith('asset3') + .mockResolvedValue(Buffer.from('false')); + +const mockReadAssetTransaction = mock(); +mockReadAssetTransaction.evaluate + .calledWith('asset1') + .mockResolvedValue(mockAsset1Buffer); +mockReadAssetTransaction.evaluate + .calledWith('asset3') + .mockRejectedValue(new Error('the asset asset3 does not exist')); + +const mockCreateAssetTransaction = mock(); +mockCreateAssetTransaction.getTransactionId.mockReturnValue('txn1'); +mockCreateAssetTransaction.submit + .calledWith('asset1') + .mockRejectedValue( + new Error( + 'No valid responses from any peers. Errors:\n peer=peer0.org1.example.com:7051, status=500, message=the asset asset1 already exists\n peer=peer0.org2.example.com:9051, status=500, message=the asset asset3 already exists' + ) + ); + +// NOTE: only the second mocked GetAllAssets with return no assets +// TODO find a better alternative so that test order does not matter +const mockGetAllAssetsTransaction = mock(); +mockGetAllAssetsTransaction.evaluate + .mockResolvedValueOnce(Buffer.from('')) + .mockResolvedValueOnce(mockAllAssetsBuffer); + +const mockUpdateAssetTransaction = mock(); +mockUpdateAssetTransaction.getTransactionId.mockReturnValue('txn1'); +mockUpdateAssetTransaction.submit + .calledWith('asset3') + .mockRejectedValue( + new Error( + 'No valid responses from any peers. Errors:\n peer=peer0.org1.example.com:7051, status=500, message=the asset asset3 does not exist\n peer=peer0.org2.example.com:9051, status=500, message=the asset asset3 does not exist' + ) + ); + +const mockTransferAssetTransaction = mock(); +mockTransferAssetTransaction.getTransactionId.mockReturnValue('txn1'); +mockTransferAssetTransaction.submit + .calledWith('asset3') + .mockRejectedValue( + new Error( + 'No valid responses from any peers. Errors:\n peer=peer0.org1.example.com:7051, status=500, message=the asset asset3 does not exist\n peer=peer0.org2.example.com:9051, status=500, message=the asset asset3 does not exist' + ) + ); + +const mockDeleteAssetTransaction = mock(); +mockDeleteAssetTransaction.getTransactionId.mockReturnValue('txn1'); +mockDeleteAssetTransaction.submit + .calledWith('asset3') + .mockRejectedValue( + new Error( + 'No valid responses from any peers. Errors:\n peer=peer0.org1.example.com:7051, status=500, message=the asset asset3 does not exist\n peer=peer0.org2.example.com:9051, status=500, message=the asset asset3 does not exist' + ) + ); + +const mockBasicContract = mock(); +mockBasicContract.createTransaction + .calledWith('AssetExists') + .mockReturnValue(mockAssetExistsTransaction); +mockBasicContract.createTransaction + .calledWith('ReadAsset') + .mockReturnValue(mockReadAssetTransaction); +mockBasicContract.createTransaction + .calledWith('CreateAsset') + .mockReturnValue(mockCreateAssetTransaction); +mockBasicContract.createTransaction + .calledWith('GetAllAssets') + .mockReturnValue(mockGetAllAssetsTransaction); +mockBasicContract.createTransaction + .calledWith('UpdateAsset') + .mockReturnValue(mockUpdateAssetTransaction); +mockBasicContract.createTransaction + .calledWith('TransferAsset') + .mockReturnValue(mockTransferAssetTransaction); +mockBasicContract.createTransaction + .calledWith('DeleteAsset') + .mockReturnValue(mockDeleteAssetTransaction); + +const mockGetTransactionByIDTransaction = mock(); +mockGetTransactionByIDTransaction.evaluate + .calledWith('mychannel', 'txn1') + .mockResolvedValue(processedTransactionBuffer); +mockGetTransactionByIDTransaction.evaluate + .calledWith('mychannel', 'txn3') + .mockRejectedValue( + new Error( + 'Failed to get transaction with id txn3, error Entry not found in index' + ) + ); + +const mockSystemContract = mock(); +mockSystemContract.evaluateTransaction + .calledWith('GetChainInfo') + .mockResolvedValue(mockBlockchainInfoBuffer); +mockSystemContract.createTransaction + .calledWith('GetTransactionByID') + .mockReturnValue(mockGetTransactionByIDTransaction); + +const mockNetwork = mock(); +mockNetwork.getContract.calledWith('basic').mockReturnValue(mockBasicContract); +mockNetwork.getContract.calledWith('qscc').mockReturnValue(mockSystemContract); + +mocked(Gateway.prototype.getNetwork).mockResolvedValue(mockNetwork); + +// TODO remove this and use simpler mocks in fabric spec tests const getMockedNetwork = (getContract = jest.fn()) => { return mocked(Gateway.prototype.getNetwork).mockResolvedValue({ getGateway: jest.fn(), @@ -47,6 +187,7 @@ const getMockedNetwork = (getContract = jest.fn()) => { export { DefaultEventHandlerStrategies, DefaultQueryHandlerStrategies, + Contract, Gateway, Wallets, getMockedNetwork, diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts index 0da71ca3..9b686f63 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts @@ -2,13 +2,15 @@ * SPDX-License-Identifier: Apache-2.0 */ +jest.mock('fabric-network'); +jest.mock('ioredis', () => require('ioredis-mock/jest')); + import { createServer } from '../server'; import { Application } from 'express'; import request from 'supertest'; -jest.mock('fabric-network'); -jest.mock('ioredis'); - +// TODO add tests for server errors +// TODO implement 405 Method Not Allowed where appropriate and add tests describe('Asset Transfer Besic REST API', () => { let app: Application; @@ -16,15 +18,593 @@ describe('Asset Transfer Besic REST API', () => { app = await createServer(); }); - describe('GET /ready', () => { - it('should respond with success json', async () => { + describe('/ready', () => { + it('GET should respond with 200 OK json', async () => { const response = await request(app).get('/ready'); expect(response.statusCode).toEqual(200); expect(response.header).toHaveProperty( 'content-type', 'application/json; charset=utf-8' ); - expect(response.body.status).toEqual('OK'); + expect(response.body).toEqual({ + status: 'OK', + timestamp: expect.any(String), + }); + }); + }); + + describe('/live', () => { + it('GET should respond with 200 OK json', async () => { + const response = await request(app).get('/live'); + expect(response.statusCode).toEqual(200); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'OK', + timestamp: expect.any(String), + }); + }); + }); + + describe('/api/assets', () => { + it('GET should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .get('/api/assets') + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('GET should respond with an empty json array when there are no assets', async () => { + // NOTE: only the first mocked GetAllAssets with return no assets + // TODO find a better alternative so that test order does not matter + const response = await request(app) + .get('/api/assets') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(200); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual([]); + }); + + it('GET should respond with json array of assets', async () => { + // NOTE: only the second mocked GetAllAssets with return no assets + // TODO find a better alternative so that test order does not matter + const response = await request(app) + .get('/api/assets') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(200); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual([ + { + ID: 'asset1', + Color: 'blue', + Size: 5, + Owner: 'Tomoko', + AppraisedValue: 300, + }, + { + ID: 'asset2', + Color: 'red', + Size: 5, + Owner: 'Brad', + AppraisedValue: 400, + }, + ]); + }); + + it('POST should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .post('/api/assets') + .send({ + ID: 'asset6', + Color: 'white', + Size: 15, + Owner: 'Michel', + AppraisedValue: 800, + }) + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('POST should respond with 400 bad request json for invalid asset json', async () => { + const response = await request(app) + .post('/api/assets') + .send({ + identifier: 'asset3', + color: 'red', + size: 5, + owner: 'Brad', + appraisedValue: 400, + }) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(400); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Bad Request', + reason: 'VALIDATION_ERROR', + errors: [ + { + location: 'body', + msg: 'must be a string', + param: 'id', + }, + ], + message: 'Invalid request body', + timestamp: expect.any(String), + }); + }); + + it('POST should respond with 202 accepted json', async () => { + const response = await request(app) + .post('/api/assets') + .send({ + id: 'asset3', + color: 'red', + size: 5, + owner: 'Brad', + appraisedValue: 400, + }) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(202); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Accepted', + transactionId: 'txn1', + timestamp: expect.any(String), + }); + }); + + it('POST should respond with 409 conflict json when asset already exists', async () => { + const response = await request(app) + .post('/api/assets') + .send({ + id: 'asset1', + color: 'blue', + size: 5, + owner: 'Tomoko', + appraisedValue: 300, + }) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(409); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Conflict', + reason: 'ASSET_EXISTS', + message: 'the asset asset1 already exists', + timestamp: expect.any(String), + }); + }); + }); + + describe('/api/assets/:id', () => { + it('OPTIONS should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .options('/api/assets/asset1') + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('OPTIONS should respond with 404 not found json without the allow header when there is no asset with the specified ID', async () => { + const response = await request(app) + .options('/api/assets/asset3') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(404); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.header).not.toHaveProperty('allow'); + expect(response.body).toEqual({ + status: 'Not Found', + timestamp: expect.any(String), + }); + }); + + it('OPTIONS should respond with 200 OK json with the allow header', async () => { + const response = await request(app) + .options('/api/assets/asset1') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(200); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.header).toHaveProperty( + 'allow', + 'DELETE,GET,OPTIONS,PATCH,PUT' + ); + expect(response.body).toEqual({ + status: 'OK', + timestamp: expect.any(String), + }); + }); + + it('GET should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .get('/api/assets/asset1') + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('GET should respond with 404 not found json when there is no asset with the specified ID', async () => { + const response = await request(app) + .get('/api/assets/asset3') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(404); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Not Found', + timestamp: expect.any(String), + }); + }); + + it('GET should respond with the asset json when the asset exists', async () => { + const response = await request(app) + .get('/api/assets/asset1') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(200); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + ID: 'asset1', + Color: 'blue', + Size: 5, + Owner: 'Tomoko', + AppraisedValue: 300, + }); + }); + + it('PUT should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .put('/api/assets/asset1') + .send({ + id: 'asset3', + color: 'red', + size: 5, + owner: 'Brad', + appraisedValue: 400, + }) + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('PUT should respond with 404 not found json when there is no asset with the specified ID', async () => { + const response = await request(app) + .put('/api/assets/asset3') + .send({ + id: 'asset3', + color: 'red', + size: 5, + owner: 'Brad', + appraisedValue: 400, + }) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(404); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Not Found', + timestamp: expect.any(String), + }); + }); + + it('PUT should respond with 400 bad request json when IDs do not match', async () => { + const response = await request(app) + .put('/api/assets/asset1') + .send({ + id: 'asset2', + color: 'red', + size: 5, + owner: 'Brad', + appraisedValue: 400, + }) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(400); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Bad Request', + reason: 'ASSET_ID_MISMATCH', + message: 'Asset IDs must match', + timestamp: expect.any(String), + }); + }); + + it('PUT should respond with 400 bad request json for invalid asset json', async () => { + const response = await request(app) + .put('/api/assets/asset1') + .send({ + identifier: 'asset1', + color: 'red', + size: 5, + owner: 'Brad', + appraisedValue: 400, + }) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(400); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Bad Request', + reason: 'VALIDATION_ERROR', + errors: [ + { + location: 'body', + msg: 'must be a string', + param: 'id', + }, + ], + message: 'Invalid request body', + timestamp: expect.any(String), + }); + }); + + it('PUT should respond with 202 accepted json', async () => { + const response = await request(app) + .put('/api/assets/asset1') + .send({ + id: 'asset1', + color: 'red', + size: 5, + owner: 'Brad', + appraisedValue: 400, + }) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(202); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Accepted', + transactionId: 'txn1', + timestamp: expect.any(String), + }); + }); + + it('PATCH should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .patch('/api/assets/asset1') + .send([{ op: 'replace', path: '/owner', value: 'Ashleigh' }]) + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('PATCH should respond with 404 not found json when there is no asset with the specified ID', async () => { + const response = await request(app) + .patch('/api/assets/asset3') + .send([{ op: 'replace', path: '/owner', value: 'Ashleigh' }]) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(404); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Not Found', + timestamp: expect.any(String), + }); + }); + + it('PATCH should respond with 400 bad request json for invalid patch op/path', async () => { + const response = await request(app) + .patch('/api/assets/asset1') + .send([{ op: 'replace', path: '/color', value: 'orange' }]) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(400); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Bad Request', + reason: 'VALIDATION_ERROR', + errors: [ + { + location: 'body', + msg: "path must be '/owner'", + param: '[0].path', + value: '/color', + }, + ], + message: 'Invalid request body', + timestamp: expect.any(String), + }); + }); + + it('PATCH should respond with 202 accepted json', async () => { + const response = await request(app) + .patch('/api/assets/asset1') + .send([{ op: 'replace', path: '/owner', value: 'Ashleigh' }]) + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(202); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Accepted', + transactionId: 'txn1', + timestamp: expect.any(String), + }); + }); + + it('DELETE should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .delete('/api/assets/asset1') + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('DELETE should respond with 404 not found json when there is no asset with the specified ID', async () => { + const response = await request(app) + .delete('/api/assets/asset3') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(404); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Not Found', + timestamp: expect.any(String), + }); + }); + + it('DELETE should respond with 202 accepted json', async () => { + const response = await request(app) + .delete('/api/assets/asset1') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(202); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Accepted', + transactionId: 'txn1', + timestamp: expect.any(String), + }); + }); + }); + + describe('/api/transactions/:id', () => { + it('GET should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .get('/api/transactions/txn1') + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('GET should respond with 404 not found json when there is no transaction with the specified ID', async () => { + const response = await request(app) + .get('/api/transactions/txn3') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(404); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Not Found', + timestamp: expect.any(String), + }); + }); + + it('GET should respond with json details for the specified transaction ID', async () => { + const response = await request(app) + .get('/api/transactions/txn1') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(200); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'OK', + progress: 'DONE', + validationCode: 'VALID', + timestamp: expect.any(String), + }); }); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index b1d89a71..eb3adb58 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -40,7 +40,10 @@ assetsRouter.get('/', async (req: Request, res: Response) => { try { const contract: Contract = getContractForOrg(req).contract; const data = await evatuateTransaction(contract, 'GetAllAssets'); - const assets = JSON.parse(data.toString()); + let assets = []; + if (data.length > 0) { + assets = JSON.parse(data.toString()); + } return res.status(OK).json(assets); } catch (err) { diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 8af4fefe..8249c55d 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -29,7 +29,7 @@ import { TransactionError, TransactionNotFoundError, } from './errors'; -import fabproto6 from 'fabric-protos'; +import protos from 'fabric-protos'; export const getNetwork = async (gateway: Gateway): Promise => { const network = await gateway.getNetwork(config.channelName); @@ -169,7 +169,9 @@ export const evatuateTransaction = async ( const txnId = txn.getTransactionId(); try { - return await txn.evaluate(...transactionArgs); + const payload = await txn.evaluate(...transactionArgs); + logger.debug({ payload }, 'Evaluate transaction response received'); + return payload; } catch (err) { throw handleError(txnId, err); } @@ -338,7 +340,7 @@ export const getChainInfo = async (qscc: Contract): Promise => { 'GetChainInfo', config.channelName ); - const info = fabproto6.common.BlockchainInfo.decode(data); + const info = protos.common.BlockchainInfo.decode(data); const blockHeight = info.height.toString(); logger.info('Current block height: %s', blockHeight); return true; From 45683b2a1a3e5ac1ddd742a17018ee1efb3c35e3 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 16 Aug 2021 17:36:37 +0100 Subject: [PATCH 077/106] Simplify fabric code Attempt to make fabric code easier to document Signed-off-by: James Taylor --- .../src/__mocks__/fabric-network.ts | 28 +-- .../rest-api-typescript/src/assets.router.ts | 36 ++-- .../rest-api-typescript/src/auth.ts | 12 +- .../rest-api-typescript/src/config.ts | 10 +- .../rest-api-typescript/src/fabric.spec.ts | 186 ++++++++++++------ .../rest-api-typescript/src/fabric.ts | 141 +++++++------ .../rest-api-typescript/src/index.ts | 9 +- .../rest-api-typescript/src/server.ts | 79 ++++---- .../src/transactions.router.ts | 7 +- 9 files changed, 274 insertions(+), 234 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts index d13ff057..626f34e6 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts @@ -3,10 +3,14 @@ */ import { mock } from 'jest-mock-extended'; -import { Contract, Network, Transaction, WalletStore } from 'fabric-network'; +import { Contract, Network, Transaction } from 'fabric-network'; import { mocked } from 'ts-jest/utils'; import * as fabricProtos from 'fabric-protos'; +const actualFabricNetwork = jest.requireActual('fabric-network'); +const Wallet = actualFabricNetwork.Wallet; +const Wallets = actualFabricNetwork.Wallets; + const mockAsset1 = { ID: 'asset1', Color: 'blue', @@ -50,15 +54,8 @@ const { DefaultEventHandlerStrategies, DefaultQueryHandlerStrategies, Gateway, - Wallet, - Wallets, }: FabricNetworkModule = jest.createMockFromModule('fabric-network'); -const mockWalletStore = mock(); -mocked(Wallets.newInMemoryWallet).mockResolvedValue( - new Wallet(mockWalletStore) -); - const mockAssetExistsTransaction = mock(); mockAssetExistsTransaction.evaluate .calledWith('asset1') @@ -171,24 +168,11 @@ mockNetwork.getContract.calledWith('qscc').mockReturnValue(mockSystemContract); mocked(Gateway.prototype.getNetwork).mockResolvedValue(mockNetwork); -// TODO remove this and use simpler mocks in fabric spec tests -const getMockedNetwork = (getContract = jest.fn()) => { - return mocked(Gateway.prototype.getNetwork).mockResolvedValue({ - getGateway: jest.fn(), - getContract, - getChannel: jest.fn(), - addCommitListener: jest.fn(), - removeCommitListener: jest.fn(), - addBlockListener: jest.fn(), - removeBlockListener: jest.fn(), - }); -}; - export { DefaultEventHandlerStrategies, DefaultQueryHandlerStrategies, Contract, Gateway, + Wallet, Wallets, - getMockedNetwork, }; diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index eb3adb58..5d75c65a 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -16,11 +16,7 @@ import { Contract } from 'fabric-network'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { Redis } from 'ioredis'; import { AssetExistsError, AssetNotFoundError } from './errors'; -import { - evatuateTransaction, - submitTransaction, - getContractForOrg, -} from './fabric'; +import { evatuateTransaction, submitTransaction } from './fabric'; import { logger } from './logger'; const { @@ -38,7 +34,9 @@ assetsRouter.get('/', async (req: Request, res: Response) => { logger.debug('Get all assets request received'); try { - const contract: Contract = getContractForOrg(req).contract; + const mspId = req.user as string; + const contract = req.app.get(mspId).assetContract as Contract; + const data = await evatuateTransaction(contract, 'GetAllAssets'); let assets = []; if (data.length > 0) { @@ -77,8 +75,9 @@ assetsRouter.post( }); } - const contract: Contract = getContractForOrg(req).contract; - const redis: Redis = req.app.get('redis'); + const mspId = req.user as string; + const contract = req.app.get(mspId).assetContract as Contract; + const redis = req.app.get('redis') as Redis; const assetId = req.body.id; try { @@ -128,7 +127,8 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { logger.debug('Asset options request received for asset ID %s', assetId); try { - const contract: Contract = getContractForOrg(req).contract; + const mspId = req.user as string; + const contract = req.app.get(mspId).assetContract as Contract; const data = await evatuateTransaction(contract, 'AssetExists', assetId); const exists = data.toString() === 'true'; @@ -167,7 +167,8 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { logger.debug('Read asset request received for asset ID %s', assetId); try { - const contract: Contract = getContractForOrg(req).contract; + const mspId = req.user as string; + const contract = req.app.get(mspId).assetContract as Contract; const data = await evatuateTransaction(contract, 'ReadAsset', assetId); const asset = JSON.parse(data.toString()); @@ -225,8 +226,9 @@ assetsRouter.put( }); } - const contract: Contract = getContractForOrg(req).contract; - const redis: Redis = req.app.get('redis'); + const mspId = req.user as string; + const contract = req.app.get(mspId).assetContract as Contract; + const redis = req.app.get('redis') as Redis; const assetId = req.params.assetId; try { @@ -294,8 +296,9 @@ assetsRouter.patch( }); } - const contract: Contract = getContractForOrg(req).contract; - const redis: Redis = req.app.get('redis'); + const mspId = req.user as string; + const contract = req.app.get(mspId).assetContract as Contract; + const redis = req.app.get('redis') as Redis; const assetId = req.params.assetId; const newOwner = req.body[0].value; @@ -339,8 +342,9 @@ assetsRouter.patch( assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { logger.debug(req.body, 'Delete asset request received'); - const contract: Contract = getContractForOrg(req).contract; - const redis: Redis = req.app.get('redis'); + const mspId = req.user as string; + const contract = req.app.get(mspId).assetContract as Contract; + const redis = req.app.get('redis') as Redis; const assetId = req.params.assetId; try { diff --git a/asset-transfer-basic/rest-api-typescript/src/auth.ts b/asset-transfer-basic/rest-api-typescript/src/auth.ts index fd40ed43..03ea8b14 100644 --- a/asset-transfer-basic/rest-api-typescript/src/auth.ts +++ b/asset-transfer-basic/rest-api-typescript/src/auth.ts @@ -17,16 +17,13 @@ export const fabricAPIKeyStrategy: HeaderAPIKeyStrategy = false, function (apikey, done) { logger.debug({ apikey }, 'Checking X-API-Key'); - const user: { org: string } = { - org: '', - }; if (apikey === config.org1ApiKey) { - user.org = config.identityNameOrg1; - logger.debug('Organisation set to Org1'); + const user = config.mspIdOrg1; + logger.debug('User set to %s', user); done(null, user); } else if (apikey === config.org2ApiKey) { - user.org = config.identityNameOrg2; - logger.info('Organisation set to Org2'); + const user = config.mspIdOrg2; + logger.debug('User set to %s', user); done(null, user); } else { logger.debug({ apikey }, 'No valid X-API-Key'); @@ -44,7 +41,6 @@ export const authenticateApiKey = ( 'headerapikey', { session: false }, (err, user, _info) => { - logger.debug({ user }, 'USERUSERUSER'); if (err) return next(err); if (!user) return res.status(UNAUTHORIZED).json({ diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 3a00c813..afc15aac 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -50,12 +50,6 @@ export const asLocalhost = env .example('true') .asBoolStrict(); -// TODO delete this and use mspIdOrg1 -export const identityNameOrg1 = 'Org1'; - -// TODO delete this and use mspIdOrg2 -export const identityNameOrg2 = 'Org2'; - /* * The Org1 MSP ID */ @@ -128,7 +122,7 @@ export const connectionProfileOrg1 = env .example( '{"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... }' ) - .asJsonObject(); + .asJsonObject() as Record; /* * Certificate for the Org1 identity @@ -157,7 +151,7 @@ export const connectionProfileOrg2 = env .example( '{"name":"test-network-org2","version":"1.0.0","client":{"organization":"Org2" ... }' ) - .asJsonObject(); + .asJsonObject() as Record; /* * Certificate for the Org2 identity diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts index 3cc7b1d8..7c37bf00 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -1,13 +1,32 @@ -import { retryTransaction, getGateway } from './fabric'; -import { getMockedNetwork } from './__mocks__/fabric-network'; +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + createGateway, + createWallet, + getContracts, + getNetwork, + retryTransaction, +} from './fabric'; import * as config from './config'; import IORedis from './__mocks__/IORedis'; import { Redis } from 'ioredis'; -import { Contract } from 'fabric-network'; +import { + Contract, + Gateway, + GatewayOptions, + Network, + Transaction, + Wallet, +} from 'fabric-network'; + +import { mock } from 'jest-mock-extended'; jest.mock('./config'); jest.mock('ioredis'); + const redisOptions = { port: config.redisPort, host: config.redisHost, @@ -17,20 +36,72 @@ const redisOptions = { const redis = new IORedis(redisOptions) as unknown as Redis; -describe('Testing retryTransaction', () => { - const transactionId = - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; - const args = '["test111","red",400,"Jean",101]'; - const timestamp = 1628078044362; - const savedTransaction = { - timestamp: timestamp.toString(), - state: state, - retries: '', - args: args, - }; +describe('Fabric', () => { + describe('createWallet', () => { + it('creates a wallet containing identities for both orgs', async () => { + const wallet = await createWallet(); - describe('Check retry increment ', () => { + expect(await wallet.list()).toStrictEqual(['Org1MSP', 'Org2MSP']); + }); + }); + + describe('createGateway', () => { + it('creates a Gateway and connects using the provided arguments', async () => { + const connectionProfile = config.connectionProfileOrg1; + const identity = config.mspIdOrg1; + const mockWallet = mock(); + + const gateway = await createGateway( + connectionProfile, + identity, + mockWallet + ); + + expect(gateway.connect).toBeCalledWith( + connectionProfile, + expect.objectContaining({ + wallet: mockWallet, + identity, + discovery: expect.any(Object), + eventHandlerOptions: expect.any(Object), + queryHandlerOptions: expect.any(Object), + }) + ); + }); + }); + + describe('getNetwork', () => { + it('gets a Network instance for the required channel from the Gateway', async () => { + const mockGateway = mock(); + + await getNetwork(mockGateway); + + expect(mockGateway.getNetwork).toHaveBeenCalledWith(config.channelName); + }); + }); + + describe('getContracts', () => { + it('gets the asset and qscc contracts from the network', async () => { + const mockBasicContract = mock(); + const mockSystemContract = mock(); + const mockNetwork = mock(); + mockNetwork.getContract + .calledWith(config.chaincodeName) + .mockReturnValue(mockBasicContract); + mockNetwork.getContract + .calledWith('qscc') + .mockReturnValue(mockSystemContract); + + const contracts = await getContracts(mockNetwork); + + expect(contracts).toStrictEqual({ + assetContract: mockBasicContract, + qsccContract: mockSystemContract, + }); + }); + }); + + describe('Testing retryTransaction', () => { const transactionId = '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; @@ -43,52 +114,53 @@ describe('Testing retryTransaction', () => { args: args, }; - it('Transaction failure, check redis increment func call', async () => { - jest.doMock('fabric-network'); - const transaction = { - submit: jest.fn().mockRejectedValue({}), + describe('Check retry increment ', () => { + const transactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; + const args = '["test111","red",400,"Jean",101]'; + const timestamp = 1628078044362; + const savedTransaction = { + timestamp: timestamp.toString(), + state: state, + retries: '', + args: args, }; - const mockedContact = { - deserializeTransaction: jest.fn().mockReturnValue(transaction), - }; - const rejectableGetContract = jest - .fn() - .mockImplementation(() => mockedContact); - const network = getMockedNetwork(rejectableGetContract)(''); - const contract: Contract = (await network).getContract(''); - savedTransaction.retries = '3'; - await retryTransaction(contract, redis, transactionId, savedTransaction); - expect(redis.hincrby).toHaveBeenCalledTimes(1); + it('Transaction failure, check redis increment func call', async () => { + const mockTransaction = mock(); + mockTransaction.submit.mockRejectedValue('MOCKERROR'); + const mockContract = mock(); + mockContract.deserializeTransaction.mockReturnValue(mockTransaction); + + savedTransaction.retries = '3'; + await retryTransaction( + mockContract, + redis, + transactionId, + savedTransaction + ); + expect(redis.hincrby).toHaveBeenCalledTimes(1); + }); }); - }); - describe('Transaction successful, check redis delete key func call ', () => { - it('call redis increment', async () => { - jest.doMock('fabric-network'); - const transaction = { - submit: jest.fn().mockResolvedValue({}), - }; - const mockedContact = { - deserializeTransaction: jest.fn().mockReturnValue(transaction), - }; - const resolvableGetContract = jest - .fn() - .mockImplementation(() => mockedContact); + describe('Transaction successful, check redis delete key func call ', () => { + it('call redis increment', async () => { + const mockTransaction = mock(); + mockTransaction.submit.mockResolvedValue(Buffer.from('{}')); + const mockContract = mock(); + mockContract.deserializeTransaction.mockReturnValue(mockTransaction); - const network = getMockedNetwork(resolvableGetContract)(''); - const contract: Contract = (await network).getContract(''); - savedTransaction.retries = '3'; - await retryTransaction(contract, redis, transactionId, savedTransaction); - expect(redis.del).toHaveBeenCalledTimes(1); + savedTransaction.retries = '3'; + await retryTransaction( + mockContract, + redis, + transactionId, + savedTransaction + ); + + expect(redis.del).toHaveBeenCalledTimes(1); + }); }); }); }); - -describe('Test getGateway', () => { - it('should throw error for invalid org name', async () => { - expect(async () => await getGateway('')).rejects.toThrow( - 'Invalid org name for gateway' - ); - }); -}); diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 8249c55d..44014ce4 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -13,8 +13,8 @@ import { BlockListener, BlockEvent, TransactionEvent, + Wallet, } from 'fabric-network'; -import { Request } from 'express'; import { Redis } from 'ioredis'; import * as config from './config'; import { logger } from './logger'; @@ -31,63 +31,60 @@ import { } from './errors'; import protos from 'fabric-protos'; -export const getNetwork = async (gateway: Gateway): Promise => { - const network = await gateway.getNetwork(config.channelName); - return network; -}; - -interface FabricConfigType { - identityName: string; - mspId: string; - connectionProfile: { [key: string]: any }; - certificate: string; - privateKey: string; -} - -const ORG1_CONFIG = { - identityName: config.identityNameOrg1, - mspId: config.mspIdOrg1, - connectionProfile: config.connectionProfileOrg1, - certificate: config.certificateOrg1, - privateKey: config.privateKeyOrg1, -}; - -const ORG2_CONFIG = { - identityName: config.identityNameOrg2, - mspId: config.mspIdOrg2, - connectionProfile: config.connectionProfileOrg2, - certificate: config.certificateOrg2, - privateKey: config.privateKeyOrg2, -}; - -const FabricDataMapper: { [key: string]: FabricConfigType } = { - [config.identityNameOrg1]: ORG1_CONFIG, - [config.identityNameOrg2]: ORG2_CONFIG, -}; - -export const getGateway = async (org: string): Promise => { - const fabricConfig = FabricDataMapper[org]; - if (fabricConfig == undefined) { - throw new Error('Invalid org name for gateway'); - } - logger.debug('Configuring fabric gateway for %s', org); +/* + * Creates an in memory wallet to hold credentials for an Org1 and Org2 user + * + * In this sample there is a single user for each MSP ID to demonstrate how + * a client app might submit transactions for different users + * + * Alternatively a REST server could use its own identity for all transactions, + * or it could use credentials supplied in the REST requests + */ +export const createWallet = async (): Promise => { const wallet = await Wallets.newInMemoryWallet(); - const x509Identity = { + const org1Identity = { credentials: { - certificate: fabricConfig.certificate, - privateKey: fabricConfig.privateKey, + certificate: config.certificateOrg1, + privateKey: config.privateKeyOrg1, }, - mspId: fabricConfig.mspId, + mspId: config.mspIdOrg1, type: 'X.509', }; - await wallet.put(fabricConfig.identityName, x509Identity); + await wallet.put(config.mspIdOrg1, org1Identity); + + const org2Identity = { + credentials: { + certificate: config.certificateOrg2, + privateKey: config.privateKeyOrg2, + }, + mspId: config.mspIdOrg2, + type: 'X.509', + }; + + await wallet.put(config.mspIdOrg2, org2Identity); + + return wallet; +}; + +/* + * Create a Gateway connection + * + * Gateway instances can and should be reused rather than connecting to submit every transaction + */ +export const createGateway = async ( + connectionProfile: Record, + identity: string, + wallet: Wallet +): Promise => { + logger.debug({ connectionProfile, identity }, 'Configuring gateway'); + const gateway = new Gateway(); - const connectOptions: GatewayOptions = { + const options: GatewayOptions = { wallet, - identity: fabricConfig.identityName, + identity, discovery: { enabled: true, asLocalhost: config.asLocalhost }, eventHandlerOptions: { commitTimeout: config.commitTimeout, @@ -100,16 +97,22 @@ export const getGateway = async (org: string): Promise => { }, }; - await gateway.connect(fabricConfig.connectionProfile, connectOptions); + await gateway.connect(connectionProfile, options); + return gateway; }; +export const getNetwork = async (gateway: Gateway): Promise => { + const network = await gateway.getNetwork(config.channelName); + return network; +}; + export const getContracts = async ( network: Network -): Promise<{ contract: Contract; qscc: Contract }> => { - const contract = network.getContract(config.chaincodeName); - const qscc = network.getContract('qscc'); - return { contract, qscc }; +): Promise<{ assetContract: Contract; qsccContract: Contract }> => { + const assetContract = network.getContract(config.chaincodeName); + const qsccContract = network.getContract('qscc'); + return { assetContract, qsccContract }; }; export const startRetryLoop = (contract: Contract, redis: Redis): void => { @@ -334,25 +337,15 @@ export const blockEventHandler = (redis: Redis): BlockListener => { return blockListner; }; -export const getChainInfo = async (qscc: Contract): Promise => { - try { - const data = await qscc.evaluateTransaction( - 'GetChainInfo', - config.channelName - ); - const info = protos.common.BlockchainInfo.decode(data); - const blockHeight = info.height.toString(); - logger.info('Current block height: %s', blockHeight); - return true; - } catch (e) { - logger.error(e, 'Unable to get blockchain info'); - return false; - } -}; - -export const getContractForOrg = ( - req: Request -): { contract: Contract; qscc: Contract } => { - const user: { org: string } = req.user as { org: string }; - return req.app.get('fabric')[user.org as string].contracts; +export const getBlockHeight = async ( + qscc: Contract +): Promise => { + const data = await qscc.evaluateTransaction( + 'GetChainInfo', + config.channelName + ); + const info = protos.common.BlockchainInfo.decode(data); + const blockHeight = info.height; + logger.debug('Current block height: %d', blockHeight); + return blockHeight; }; diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 94814eb6..722079c5 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -12,10 +12,11 @@ import { createServer } from './server'; async function main() { const app = await createServer(); - const contract: Contract = - app.get('fabric')[config.identityNameOrg1].contracts.contract; - const redis: Redis = app.get('redis'); - const network: Network = app.get('fabric')[config.identityNameOrg1].network; + // TODO block listener and retry logic currently only handles a single org!!! + // TODO should these be initialised here? + const contract = app.get(config.mspIdOrg1).assetContract as Contract; + const redis = app.get('redis') as Redis; + const network = app.get('networkOrg1') as Network; await network.addBlockListener(blockEventHandler(redis)); startRetryLoop(contract, redis); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 5caf5799..4aeed8dd 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -12,10 +12,10 @@ import { assetsRouter } from './assets.router'; import { transactionsRouter } from './transactions.router'; import { getContracts, - getGateway, getNetwork, - getChainInfo, - getContractForOrg, + getBlockHeight, + createGateway, + createWallet, } from './fabric'; import { redis } from './redis'; import { Contract } from 'fabric-network'; @@ -74,29 +74,29 @@ export const createServer = async (): Promise => { if (process.env.NODE_ENV === 'production') { app.use(helmet()); } - // - const gatewayOrg1 = await getGateway(config.identityNameOrg1); - const gatewayOrg2 = await getGateway(config.identityNameOrg2); + + const wallet = await createWallet(); + + const gatewayOrg1 = await createGateway( + config.connectionProfileOrg1, + config.mspIdOrg1, + wallet + ); const networkOrg1 = await getNetwork(gatewayOrg1); - const networkOrg2 = await getNetwork(gatewayOrg2); - const contractsOrg1 = await getContracts(networkOrg1); + app.set(config.mspIdOrg1, contractsOrg1); + + // TODO used for block listener, which needs fixing! + app.set('networkOrg1', networkOrg1); + + const gatewayOrg2 = await createGateway( + config.connectionProfileOrg2, + config.mspIdOrg2, + wallet + ); + const networkOrg2 = await getNetwork(gatewayOrg2); const contractsOrg2 = await getContracts(networkOrg2); - - const fabric = { - [config.identityNameOrg1]: { - gateway: gatewayOrg1, - contracts: contractsOrg1, - network: networkOrg1, - }, - [config.identityNameOrg2]: { - gateway: gatewayOrg2, - contracts: contractsOrg2, - network: networkOrg2, - }, - }; - - app.set('fabric', fabric); + app.set(config.mspIdOrg2, contractsOrg2); app.set('redis', redis); @@ -107,32 +107,27 @@ export const createServer = async (): Promise => { timestamp: new Date().toISOString(), }) ); - app.get('/live', async (_req, res) => { - _req.user = { org: config.identityNameOrg1 }; - const qsccOrg1: Contract = getContractForOrg(_req).qscc; - const Org1Liveness = await getChainInfo(qsccOrg1); - logger.debug('Org1 liveness %s', Org1Liveness); - _req.user = { org: config.identityNameOrg2 }; - const qsccOrg2: Contract = getContractForOrg(_req).qscc; - const Org2Liveness = await getChainInfo(qsccOrg2); - logger.debug('Org2 liveness %s', Org2Liveness); + app.get('/live', async (req, res) => { + logger.debug(req.body, 'Liveness request received'); + + const qsccOrg1 = req.app.get(config.mspIdOrg1).qsccContract as Contract; + const qsccOrg2 = req.app.get(config.mspIdOrg2).qsccContract as Contract; + + try { + await Promise.all([getBlockHeight(qsccOrg1), getBlockHeight(qsccOrg2)]); + } catch (err) { + logger.error(err, 'Error processing liveness request'); - if (Org1Liveness && Org2Liveness) { - res.status(OK).json({ - status: getReasonPhrase(OK), - timestamp: new Date().toISOString(), - }); - } else { res.status(SERVICE_UNAVAILABLE).json({ status: getReasonPhrase(SERVICE_UNAVAILABLE), timestamp: new Date().toISOString(), }); } - }); - // TODO delete me - app.get('/error', (_req, _res) => { - throw new Error('Example error'); + res.status(OK).json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }); }); app.use('/api/assets', authenticateApiKey, assetsRouter); diff --git a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts index c3dd49bf..27f6438b 100644 --- a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts @@ -7,7 +7,7 @@ import { Contract } from 'fabric-network'; import { protos } from 'fabric-protos'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { Redis } from 'ioredis'; -import { evatuateTransaction, getContractForOrg } from './fabric'; +import { evatuateTransaction } from './fabric'; import { logger } from './logger'; import * as config from './config'; import { TransactionNotFoundError } from './errors'; @@ -28,8 +28,9 @@ transactionsRouter.get( let progress: Progress = 'DONE'; let validationCode = ''; - const qscc: Contract = getContractForOrg(req).qscc; - const redis: Redis = req.app.get('redis'); + const mspId = req.user as string; + const qscc = req.app.get(mspId).qsccContract as Contract; + const redis = req.app.get('redis') as Redis; try { const savedTransaction = await (redis as Redis).hgetall( From 5d1adddd03df1bd11329987167ac13f4a6639519 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 18 Aug 2021 09:42:06 +0100 Subject: [PATCH 078/106] Refactor health routes in to separate file Signed-off-by: James Taylor --- .../rest-api-typescript/src/health.router.ts | 48 +++++++++++++++++++ .../rest-api-typescript/src/server.ts | 43 ++--------------- 2 files changed, 51 insertions(+), 40 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/health.router.ts diff --git a/asset-transfer-basic/rest-api-typescript/src/health.router.ts b/asset-transfer-basic/rest-api-typescript/src/health.router.ts new file mode 100644 index 00000000..27b40c3d --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/health.router.ts @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import express, { Request, Response } from 'express'; +import { Contract } from 'fabric-network'; +import { getReasonPhrase, StatusCodes } from 'http-status-codes'; +import { getBlockHeight } from './fabric'; +import { logger } from './logger'; +import * as config from './config'; + +const { SERVICE_UNAVAILABLE, OK } = StatusCodes; + +export const healthRouter = express.Router(); + +/* + * Example of possible health endpoints for use in a cloud environment + */ + +healthRouter.get('/ready', (_req, res: Response) => + res.status(OK).json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }) +); + +healthRouter.get('/live', async (req: Request, res: Response) => { + logger.debug(req.body, 'Liveness request received'); + + const qsccOrg1 = req.app.get(config.mspIdOrg1).qsccContract as Contract; + const qsccOrg2 = req.app.get(config.mspIdOrg2).qsccContract as Contract; + + try { + await Promise.all([getBlockHeight(qsccOrg1), getBlockHeight(qsccOrg2)]); + } catch (err) { + logger.error(err, 'Error processing liveness request'); + + res.status(SERVICE_UNAVAILABLE).json({ + status: getReasonPhrase(SERVICE_UNAVAILABLE), + timestamp: new Date().toISOString(), + }); + } + + res.status(OK).json({ + status: getReasonPhrase(OK), + timestamp: new Date().toISOString(), + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 4aeed8dd..14674a1c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -9,24 +9,17 @@ import pinoMiddleware from 'pino-http'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; +import { healthRouter } from './health.router'; import { transactionsRouter } from './transactions.router'; import { getContracts, getNetwork, - getBlockHeight, createGateway, createWallet, } from './fabric'; import { redis } from './redis'; -import { Contract } from 'fabric-network'; import * as config from './config'; -const { - BAD_REQUEST, - INTERNAL_SERVER_ERROR, - NOT_FOUND, - OK, - SERVICE_UNAVAILABLE, -} = StatusCodes; +const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND } = StatusCodes; import { authenticateApiKey, fabricAPIKeyStrategy } from './auth'; import passport from 'passport'; @@ -100,36 +93,7 @@ export const createServer = async (): Promise => { app.set('redis', redis); - // Health routes - app.get('/ready', (_req, res) => - res.status(OK).json({ - status: getReasonPhrase(OK), - timestamp: new Date().toISOString(), - }) - ); - app.get('/live', async (req, res) => { - logger.debug(req.body, 'Liveness request received'); - - const qsccOrg1 = req.app.get(config.mspIdOrg1).qsccContract as Contract; - const qsccOrg2 = req.app.get(config.mspIdOrg2).qsccContract as Contract; - - try { - await Promise.all([getBlockHeight(qsccOrg1), getBlockHeight(qsccOrg2)]); - } catch (err) { - logger.error(err, 'Error processing liveness request'); - - res.status(SERVICE_UNAVAILABLE).json({ - status: getReasonPhrase(SERVICE_UNAVAILABLE), - timestamp: new Date().toISOString(), - }); - } - - res.status(OK).json({ - status: getReasonPhrase(OK), - timestamp: new Date().toISOString(), - }); - }); - + app.use('/', healthRouter); app.use('/api/assets', authenticateApiKey, assetsRouter); app.use('/api/transactions', authenticateApiKey, transactionsRouter); @@ -142,7 +106,6 @@ export const createServer = async (): Promise => { ); // Print API errors - // TBC in addition to pinoMiddleware errors? app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => { logger.error(err); return res.status(INTERNAL_SERVER_ERROR).json({ From 82b1249f4e5cf4998037527300db8b67a874bcaf Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 18 Aug 2021 17:01:04 +0100 Subject: [PATCH 079/106] Improve Docker support - default command should be start, rather than start:dev in the docker image - added a multistage build - fixed node-gyp error - removed dev dependencies - added a start:dotenv script to support a .env file in production (may be useful for k8s later) - updated Readme and generateEnv script to simplify the setup - updated external network in docker-compose.yaml to match the test network Signed-off-by: James Taylor --- README.md | 41 ++++++++++--------- .../rest-api-typescript/.env.sample | 15 ++++--- .../rest-api-typescript/Dockerfile | 27 +++++++----- .../rest-api-typescript/docker-compose.yaml | 12 +++--- .../rest-api-typescript/package.json | 1 + .../scripts/generateEnv.sh | 40 ++++++++++++++---- 6 files changed, 85 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index b5f40edf..06f58ab8 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,28 @@ Start the sample REST server npm run start:dev ``` +### Docker image + +Alternatively, run the following commands in the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory to start the sample in a Docker container + +Build the Docker image + +```shell +docker build -t fabric-rest-sample . +``` + +Create a `.env` file to configure the server for the test network (make sure `TEST_NETWORK_HOME` is set to the fully qualified `test-network` directory and `AS_LOCAL_HOST` is set to `false` so that the server works inside the Docker Compose network) + +```shell +TEST_NETWORK_HOME=$HOME/fabric-samples/test-network AS_LOCAL_HOST=false npm run generateEnv +``` + +Start the sample REST server and Redis server + +```shell +docker-compose up -d +``` + ## REST API If everything went well, you can now make basic asset transfer REST calls! @@ -105,22 +127,3 @@ curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${ ```shell curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request DELETE http://localhost:3000/api/assets/asset7 ``` -## Steps to run the application using docker: - -Move to directory fabric-rest-sample/asset-transfer-basic/rest-api-typescript - -### Build docker image - docker build -t fabricapp . - -### Generate .env file - TEST_NETWORK_HOME=$HOME/fabric-samples/test-network ./scripts/generateEnv.sh - - Note: Connection profile need to use the peer container’s hostname instead of localhost. - -### Run docker containers - docker-compose up -d - - - - - diff --git a/asset-transfer-basic/rest-api-typescript/.env.sample b/asset-transfer-basic/rest-api-typescript/.env.sample index f81d0dcf..dc052b68 100644 --- a/asset-transfer-basic/rest-api-typescript/.env.sample +++ b/asset-transfer-basic/rest-api-typescript/.env.sample @@ -4,6 +4,10 @@ PORT=3000 RETRY_DELAY=3000 +MAX_RETRY_COUNT=5 + +AS_LOCAL_HOST=true + HLF_CONNECTION_PROFILE_ORG1={"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... } HLF_CERTIFICATE_ORG1="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" @@ -16,19 +20,20 @@ HLF_CERTIFICATE_ORG2="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE---- HLF_PRIVATE_KEY_ORG2="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" - HLF_COMMIT_TIMEOUT=3000 HLF_ENDORSE_TIMEOUT=30 +HLF_QUERY_TIMEOUT=3 + REDIS_HOST=localhost REDIS_PORT=6379 -ORG1_APIKEY=D2F66BFF-D68B-458D-8FA6-285F172D5B03 - -ORG2_APIKEY=92042C1F-8E58-48F9-9EAF-91A98A2B7648 - #REDIS_USERNAME= #REDIS_PASSWORD= + +ORG1_APIKEY=D2F66BFF-D68B-458D-8FA6-285F172D5B03 + +ORG2_APIKEY=92042C1F-8E58-48F9-9EAF-91A98A2B764 diff --git a/asset-transfer-basic/rest-api-typescript/Dockerfile b/asset-transfer-basic/rest-api-typescript/Dockerfile index 5ebc77bd..073c68f1 100644 --- a/asset-transfer-basic/rest-api-typescript/Dockerfile +++ b/asset-transfer-basic/rest-api-typescript/Dockerfile @@ -1,20 +1,25 @@ -FROM node:14-alpine3.12 -RUN apk add dumb-init -WORKDIR /fabric_app/ +FROM node:14-alpine3.12 AS build -COPY --chown=node:node . /fabric_app/ +RUN apk add --no-cache g++ make python3 dumb-init -RUN npm ci +WORKDIR /app +COPY --chown=node:node . /app + +RUN npm ci RUN npm run build +RUN npm prune --production + +FROM node:14-alpine3.12 +ENV NODE_ENV production +WORKDIR /app + +COPY --from=build /usr/bin/dumb-init /usr/bin/dumb-init +COPY --chown=node:node --from=build /app . EXPOSE 3000 USER node -CMD dumb-init npm run start:dev - - - - - +ENTRYPOINT [ "dumb-init", "--", "npm", "run"] +CMD ["start"] diff --git a/asset-transfer-basic/rest-api-typescript/docker-compose.yaml b/asset-transfer-basic/rest-api-typescript/docker-compose.yaml index 1a2c7b93..b7c4b0b3 100644 --- a/asset-transfer-basic/rest-api-typescript/docker-compose.yaml +++ b/asset-transfer-basic/rest-api-typescript/docker-compose.yaml @@ -6,21 +6,19 @@ services: ports: - 6379:6379 networks: - - net_test + - fabric_test nodeapp: - image: 'fabricapp' + image: 'fabric-rest-sample' + command: ['start:dotenv'] ports: - 3000:3000 env_file: - ./.env - environment: - - REDIS_HOST=redis - - AS_LOCAL_HOST=false networks: - - net_test + - fabric_test networks: - net_test: + fabric_test: external: true diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index 18919584..815f9e19 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -51,6 +51,7 @@ "generateEnv": "./scripts/generateEnv.sh", "lint": "eslint . --ext .ts", "start": "node --require source-map-support/register ./dist", + "start:dotenv": "node --require source-map-support/register --require dotenv/config ./dist", "start:dev": "node --require source-map-support/register --require dotenv/config ./dist | pino-pretty", "start:redis": "docker run -p 6379:6379 --name fabric-sample-redis -d redis", "test": "jest" diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index 902397f8..c910651e 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -4,6 +4,8 @@ # SPDX-License-Identifier: Apache-2.0 # +${AS_LOCAL_HOST:=true} + : "${TEST_NETWORK_HOME:=../..}" : "${CONNECTION_PROFILE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" : "${CERTIFICATE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem}" @@ -23,14 +25,10 @@ RETRY_DELAY=3000 MAX_RETRY_COUNT=5 -HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .) - HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" HLF_PRIVATE_KEY_ORG1="$(cat ${PRIVATE_KEY_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" -HLF_CONNECTION_PROFILE_ORG2=$(cat ${CONNECTION_PROFILE_FILE_ORG2} | jq -c .) - HLF_CERTIFICATE_ORG2="$(cat ${CERTIFICATE_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" HLF_PRIVATE_KEY_ORG2="$(cat ${PRIVATE_KEY_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" @@ -39,7 +37,7 @@ HLF_COMMIT_TIMEOUT=3000 HLF_ENDORSE_TIMEOUT=30 -REDIS_HOST=localhost +HLF_QUERY_TIMEOUT=3 REDIS_PORT=6379 @@ -47,8 +45,32 @@ ORG1_APIKEY=$(uuidgen) ORG2_APIKEY=$(uuidgen) -#REDIS_USERNAME= - -#REDIS_PASSWORD= - ENV_END + +if [ "${AS_LOCAL_HOST}" = "true" ]; then + +cat << LOCAL_HOST_END >> .env +AS_LOCAL_HOST=true + +HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c .) + +HLF_CONNECTION_PROFILE_ORG2=$(cat ${CONNECTION_PROFILE_FILE_ORG2} | jq -c .) + +REDIS_HOST=localhost + +LOCAL_HOST_END + +elif [ "${AS_LOCAL_HOST}" = "false" ]; then + +cat << WITH_HOSTNAME_END >> .env +AS_LOCAL_HOST=false + +HLF_CONNECTION_PROFILE_ORG1=$(cat ${CONNECTION_PROFILE_FILE_ORG1} | jq -c '.peers["peer0.org1.example.com"].url = "grpcs://peer0.org1.example.com:7051" | .certificateAuthorities["ca.org1.example.com"].url = "https://ca.org1.example.com:7054"') + +HLF_CONNECTION_PROFILE_ORG2=$(cat ${CONNECTION_PROFILE_FILE_ORG2} | jq -c '.peers["peer0.org2.example.com"].url = "grpcs://peer0.org2.example.com:9051" | .certificateAuthorities["ca.org2.example.com"].url = "https://ca.org2.example.com:8054"') + +REDIS_HOST=redis + +WITH_HOSTNAME_END + +fi From bf91df7ef3dc4ee9cf01070fa097fac0df08702e Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 17 Aug 2021 17:34:45 +0100 Subject: [PATCH 080/106] Update transaction retry to use correct user Also improves test coverage Signed-off-by: James Taylor --- .../src/__mocks__/IORedis.ts | 21 - .../src/__mocks__/fabric-network.ts | 2 +- .../src/__tests__/api.test.ts | 2 +- .../rest-api-typescript/src/assets.router.ts | 4 + .../rest-api-typescript/src/fabric.spec.ts | 452 +++++++++++++++--- .../rest-api-typescript/src/fabric.ts | 137 +++--- .../rest-api-typescript/src/index.ts | 11 +- .../rest-api-typescript/src/logger.ts | 4 + .../rest-api-typescript/src/redis.spec.ts | 225 ++++++--- .../rest-api-typescript/src/redis.ts | 126 ++++- .../rest-api-typescript/src/server.ts | 7 + .../src/transactions.router.ts | 15 +- 12 files changed, 776 insertions(+), 230 deletions(-) delete mode 100644 asset-transfer-basic/rest-api-typescript/src/__mocks__/IORedis.ts diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/IORedis.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/IORedis.ts deleted file mode 100644 index bc31167e..00000000 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/IORedis.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { RedisOptions } from 'ioredis'; - -class IORedis { - redisOptions: RedisOptions; - constructor(options: RedisOptions) { - this.redisOptions = options; - } - - hincrby = jest.fn().mockReturnThis(); - multi = jest.fn().mockReturnThis(); - del = jest.fn().mockReturnThis(); - - zrem = jest.fn().mockReturnThis(); - - exec = jest.fn().mockReturnThis(); - - hset = jest.fn().mockReturnThis(); - zadd = jest.fn().mockReturnThis(); -} - -export default IORedis; diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts index 626f34e6..4f58ae24 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts @@ -144,7 +144,7 @@ mockBasicContract.createTransaction const mockGetTransactionByIDTransaction = mock(); mockGetTransactionByIDTransaction.evaluate - .calledWith('mychannel', 'txn1') + .calledWith('mychannel', 'txn2') .mockResolvedValue(processedTransactionBuffer); mockGetTransactionByIDTransaction.evaluate .calledWith('mychannel', 'txn3') diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts index 9b686f63..5b065426 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts @@ -592,7 +592,7 @@ describe('Asset Transfer Besic REST API', () => { it('GET should respond with json details for the specified transaction ID', async () => { const response = await request(app) - .get('/api/transactions/txn1') + .get('/api/transactions/txn2') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); expect(response.statusCode).toEqual(200); expect(response.header).toHaveProperty( diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 5d75c65a..6bac3866 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -84,6 +84,7 @@ assetsRouter.post( const transactionId = await submitTransaction( contract, redis, + mspId, 'CreateAsset', assetId, req.body.color, @@ -235,6 +236,7 @@ assetsRouter.put( const transactionId = await submitTransaction( contract, redis, + mspId, 'UpdateAsset', assetId, req.body.color, @@ -306,6 +308,7 @@ assetsRouter.patch( const transactionId = await submitTransaction( contract, redis, + mspId, 'TransferAsset', assetId, newOwner @@ -351,6 +354,7 @@ assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { const transactionId = await submitTransaction( contract, redis, + mspId, 'DeleteAsset', assetId ); diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts index 7c37bf00..b74ddf7a 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -7,12 +7,20 @@ import { createWallet, getContracts, getNetwork, - retryTransaction, + evatuateTransaction, + submitTransaction, + getBlockHeight, + startRetryLoop, } from './fabric'; import * as config from './config'; -import IORedis from './__mocks__/IORedis'; -import { Redis } from 'ioredis'; +import { + AssetExistsError, + AssetNotFoundError, + TransactionError, + TransactionNotFoundError, +} from './errors'; + import { Contract, Gateway, @@ -22,19 +30,14 @@ import { Wallet, } from 'fabric-network'; -import { mock } from 'jest-mock-extended'; +import * as fabricProtos from 'fabric-protos'; + +import { MockProxy, mock } from 'jest-mock-extended'; +import IORedis, { Redis } from 'ioredis'; +import Long from 'long'; jest.mock('./config'); -jest.mock('ioredis'); - -const redisOptions = { - port: config.redisPort, - host: config.redisHost, - username: config.redisUsername, - password: config.redisPassword, -}; - -const redis = new IORedis(redisOptions) as unknown as Redis; +jest.mock('ioredis', () => require('ioredis-mock/jest')); describe('Fabric', () => { describe('createWallet', () => { @@ -101,66 +104,393 @@ describe('Fabric', () => { }); }); - describe('Testing retryTransaction', () => { - const transactionId = + describe('startRetryLoop', () => { + let redis: Redis; + let mockTransaction: MockProxy; + let mockContract: MockProxy; + let mockContracts: Map; + + const mockTransactionId = '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; - const args = '["test111","red",400,"Jean",101]'; - const timestamp = 1628078044362; - const savedTransaction = { - timestamp: timestamp.toString(), - state: state, - retries: '', - args: args, + const mockKey = `txn:${mockTransactionId}`; + const mockMspId = 'Org1MSP'; + const mockState = Buffer.from( + `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${mockTransactionId}` + ); + const mockArgs = '["test111","red",400,"Jean",101]'; + const mockTimestamp = 1628078044362; + + const flushPromises = () => { + jest.useRealTimers(); + return new Promise((resolve) => setImmediate(resolve)); }; - describe('Check retry increment ', () => { - const transactionId = - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; - const args = '["test111","red",400,"Jean",101]'; - const timestamp = 1628078044362; - const savedTransaction = { - timestamp: timestamp.toString(), - state: state, - retries: '', - args: args, + const addMockTransationDetails = async (redis: Redis) => { + await redis + .multi() + .hset( + mockKey, + 'mspId', + mockMspId, + 'state', + mockState, + 'args', + mockArgs, + 'timestamp', + mockTimestamp, + 'retries', + '0' + ) + .zadd('index:txn:timestamp', mockTimestamp, mockTransactionId) + .exec(); + }; + + beforeEach(() => { + const redisOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, }; - it('Transaction failure, check redis increment func call', async () => { - const mockTransaction = mock(); - mockTransaction.submit.mockRejectedValue('MOCKERROR'); - const mockContract = mock(); - mockContract.deserializeTransaction.mockReturnValue(mockTransaction); + redis = new IORedis(redisOptions) as unknown as Redis; - savedTransaction.retries = '3'; - await retryTransaction( - mockContract, - redis, - transactionId, - savedTransaction - ); - expect(redis.hincrby).toHaveBeenCalledTimes(1); - }); + mockTransaction = mock(); + mockTransaction.submit + .mockResolvedValue(Buffer.from('MOCK PAYLOAD')) + .mockName('submit'); + mockContract = mock(); + mockContract.deserializeTransaction.mockReturnValue(mockTransaction); + mockContracts = new Map(); + mockContracts.set(mockMspId, mockContract); + + jest.useFakeTimers(); }); - describe('Transaction successful, check redis delete key func call ', () => { - it('call redis increment', async () => { - const mockTransaction = mock(); - mockTransaction.submit.mockResolvedValue(Buffer.from('{}')); - const mockContract = mock(); - mockContract.deserializeTransaction.mockReturnValue(mockTransaction); + afterEach(() => { + jest.useRealTimers(); + }); - savedTransaction.retries = '3'; - await retryTransaction( + it('starts a retry loop which does nothing if there are no saved transaction details', async () => { + const getContractSpy = jest.spyOn(mockContracts, 'get'); + + startRetryLoop(mockContracts, redis); + jest.runOnlyPendingTimers(); + await flushPromises(); + + expect(getContractSpy).not.toBeCalled(); + }); + + it('starts a retry loop which clears the saved details after succesfully retrying a transaction', async () => { + addMockTransationDetails(redis); + + startRetryLoop(mockContracts, redis); + jest.runOnlyPendingTimers(); + await flushPromises(); + + expect(mockContract.deserializeTransaction).toBeCalledWith(mockState); + expect(mockTransaction.submit).toBeCalledWith( + 'test111', + 'red', + 400, + 'Jean', + 101 + ); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([]); + }); + + it('starts a retry loop which increments the retry count when a transaction fails', async () => { + addMockTransationDetails(redis); + mockTransaction.submit.mockRejectedValue(new Error('MOCK ERROR')); + + startRetryLoop(mockContracts, redis); + jest.runOnlyPendingTimers(); + await flushPromises(); + + expect(mockContract.deserializeTransaction).toBeCalledWith(mockState); + expect(mockTransaction.submit).toBeCalledWith( + 'test111', + 'red', + 400, + 'Jean', + 101 + ); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([ + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95', + ]); + + const savedTransaction = await (redis as Redis).hgetall(mockKey); + expect(savedTransaction.retries).toBe('1'); + }); + + it('starts a retry loop which clears the saved details when a transaction fails as a duplicate', async () => { + addMockTransationDetails(redis); + const mockDuplicateTransactionError = new Error('MOCK ERROR'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (mockDuplicateTransactionError as any).errors = [ + { + endorsements: [ + { + details: 'duplicate transaction found', + }, + ], + }, + ]; + mockTransaction.submit.mockRejectedValue(mockDuplicateTransactionError); + + startRetryLoop(mockContracts, redis); + jest.runOnlyPendingTimers(); + await flushPromises(); + + expect(mockContract.deserializeTransaction).toBeCalledWith(mockState); + expect(mockTransaction.submit).toBeCalledWith( + 'test111', + 'red', + 400, + 'Jean', + 101 + ); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([]); + }); + + it('starts a retry loop which clears the saved details when a transaction fails the final attempt', async () => { + addMockTransationDetails(redis); + await (redis as Redis).hincrby(mockKey, 'retries', 5); + mockTransaction.submit.mockRejectedValue(new Error('MOCK ERROR')); + + startRetryLoop(mockContracts, redis); + jest.runOnlyPendingTimers(); + await flushPromises(); + + expect(mockContract.deserializeTransaction).toBeCalledWith(mockState); + expect(mockTransaction.submit).toBeCalledWith( + 'test111', + 'red', + 400, + 'Jean', + 101 + ); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([]); + }); + }); + + describe('evatuateTransaction', () => { + const mockPayload = Buffer.from('MOCK PAYLOAD'); + let mockTransaction: MockProxy; + let mockContract: MockProxy; + + beforeEach(() => { + mockTransaction = mock(); + mockTransaction.evaluate.mockResolvedValue(mockPayload); + mockContract = mock(); + mockContract.createTransaction + .calledWith('txn') + .mockReturnValue(mockTransaction); + }); + + it('gets the result of evaluating a transaction', async () => { + const result = await evatuateTransaction( + mockContract, + 'txn', + 'arga', + 'argb' + ); + expect(result.toString()).toBe(mockPayload.toString()); + }); + + it.each([ + 'the asset GOCHAINCODE already exists', + 'Asset JAVACHAINCODE already exists', + 'The asset JSCHAINCODE already exists', + ])( + 'throws an AssetExistsError an asset already exists error occurs: %s', + async (msg) => { + mockTransaction.evaluate.mockRejectedValue(new Error(msg)); + + await expect(async () => { + await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); + }).rejects.toThrow(AssetExistsError); + } + ); + + it.each([ + 'the asset GOCHAINCODE does not exist', + 'Asset JAVACHAINCODE does not exist', + 'The asset JSCHAINCODE does not exist', + ])( + 'throws an AssetNotFoundError if an asset does not exist error occurs: %s', + async (msg) => { + mockTransaction.evaluate.mockRejectedValue(new Error(msg)); + + await expect(async () => { + await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); + }).rejects.toThrow(AssetNotFoundError); + } + ); + + it('throws a TransactionNotFoundError if a transaction not found error occurs', async () => { + mockTransaction.evaluate.mockRejectedValue( + new Error( + 'Failed to get transaction with id txn, error Entry not found in index' + ) + ); + + await expect(async () => { + await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); + }).rejects.toThrow(TransactionNotFoundError); + }); + + it('throws a TransactionError for other errors', async () => { + mockTransaction.evaluate.mockRejectedValue(new Error('MOCK ERROR')); + + await expect(async () => { + await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); + }).rejects.toThrow(TransactionError); + }); + }); + + describe('submitTransaction', () => { + let redis: Redis; + const mockPayload = Buffer.from('MOCK PAYLOAD'); + let mockTransaction: MockProxy; + let mockContract: MockProxy; + + beforeEach(async () => { + const redisOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, + }; + + redis = new IORedis(redisOptions) as unknown as Redis; + + mockTransaction = mock(); + mockTransaction.submit.mockResolvedValue(mockPayload); + mockTransaction.getTransactionId.mockReturnValue('MOCK TXN ID'); + mockTransaction.serialize.mockReturnValue(Buffer.from('MOCK TXN STATE')); + mockContract = mock(); + mockContract.createTransaction + .calledWith('txn') + .mockReturnValue(mockTransaction); + }); + + it('gets the transaction ID of the submitted transaction', async () => { + const result = await submitTransaction( + mockContract, + redis, + 'mspid', + 'txn', + 'arga', + 'argb' + ); + expect(result).toBe('MOCK TXN ID'); + }); + + it.each([ + 'the asset GOCHAINCODE already exists', + 'Asset JAVACHAINCODE already exists', + 'The asset JSCHAINCODE already exists', + ])( + 'throws an AssetExistsError an asset already exists error occurs: %s', + async (msg) => { + mockTransaction.submit.mockRejectedValue(new Error(msg)); + + await expect(async () => { + await submitTransaction( + mockContract, + redis, + 'mspid', + 'txn', + 'arga', + 'argb' + ); + }).rejects.toThrow(AssetExistsError); + } + ); + + it.each([ + 'the asset GOCHAINCODE does not exist', + 'Asset JAVACHAINCODE does not exist', + 'The asset JSCHAINCODE does not exist', + ])( + 'throws an AssetNotFoundError if an asset does not exist error occurs: %s', + async (msg) => { + mockTransaction.submit.mockRejectedValue(new Error(msg)); + + await expect(async () => { + await submitTransaction( + mockContract, + redis, + 'mspid', + 'txn', + 'arga', + 'argb' + ); + }).rejects.toThrow(AssetNotFoundError); + } + ); + + it('throws a TransactionNotFoundError if a transaction not found error occurs', async () => { + mockTransaction.submit.mockRejectedValue( + new Error( + 'Failed to get transaction with id txn, error Entry not found in index' + ) + ); + + await expect(async () => { + await submitTransaction( mockContract, redis, - transactionId, - savedTransaction + 'mspid', + 'txn', + 'arga', + 'argb' ); + }).rejects.toThrow(TransactionNotFoundError); + }); - expect(redis.del).toHaveBeenCalledTimes(1); - }); + it('throws a TransactionError for other errors', async () => { + mockTransaction.submit.mockRejectedValue(new Error('MOCK ERROR')); + + await expect(async () => { + await submitTransaction( + mockContract, + redis, + 'mspid', + 'txn', + 'arga', + 'argb' + ); + }).rejects.toThrow(TransactionError); + }); + }); + + describe('getBlockHeight', () => { + it('gets the current block height', async () => { + const mockBlockchainInfoProto = + fabricProtos.common.BlockchainInfo.create(); + mockBlockchainInfoProto.height = 42; + const mockBlockchainInfoBuffer = Buffer.from( + fabricProtos.common.BlockchainInfo.encode( + mockBlockchainInfoProto + ).finish() + ); + const mockContract = mock(); + mockContract.evaluateTransaction + .calledWith('GetChainInfo', 'mychannel') + .mockResolvedValue(mockBlockchainInfoBuffer); + + const result = (await getBlockHeight(mockContract)) as Long; + expect(result.toInt()).toStrictEqual(42); }); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 44014ce4..363f9c72 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -20,8 +20,10 @@ import * as config from './config'; import { logger } from './logger'; import { storeTransactionDetails, + getRetryTransactionDetails, clearTransactionDetails, incrementRetryCount, + TransactionDetails, } from './redis'; import { AssetExistsError, @@ -115,52 +117,48 @@ export const getContracts = async ( return { assetContract, qsccContract }; }; -export const startRetryLoop = (contract: Contract, redis: Redis): void => { - setInterval( - async (redis) => { - try { - const pendingTransactionCount = await (redis as Redis).zcard( - 'index:txn:timestamp' - ); - logger.debug( - 'Transactions awaiting retry: %d', - pendingTransactionCount - ); - - // TODO pick a random transaction instead to reduce chances of - // clashing with other instances? Currently no zrandmember - // command though... - // https://github.com/luin/ioredis/issues/1374 - const transactionIds = await (redis as Redis).zrange( - 'index:txn:timestamp', - -1, - -1 - ); - - if (transactionIds.length > 0) { - const transactionId = transactionIds[0]; - const savedTransaction = await (redis as Redis).hgetall( - `txn:${transactionId}` +export const startRetryLoop = ( + contracts: Map, + redis: Redis +): void => { + const retryInterval = setInterval( + async (contracts, redis) => { + if (logger.isLevelEnabled('debug')) { + try { + const pendingTransactionCount = await (redis as Redis).zcard( + 'index:txn:timestamp' + ); + logger.debug( + '%d transactions awaiting retry', + pendingTransactionCount + ); + } catch (err) { + logger.warn({ err }, 'Error getting pending transaction count'); + } + } + + const savedTransaction = await getRetryTransactionDetails(redis); + + if (savedTransaction) { + const contract = contracts.get(savedTransaction.mspId); + + if (contract) { + await retryTransaction(contract, redis, savedTransaction); + } else { + logger.error( + 'No contract found for %s to retry transaction %s', + savedTransaction.mspId, + savedTransaction.transactionId ); - if (parseInt(savedTransaction.retries) >= config.maxRetryCount) { - await clearTransactionDetails(redis, transactionId); - } else { - await retryTransaction( - contract, - redis, - transactionId, - savedTransaction - ); - } } - } catch (err) { - // TODO just log? - logger.error(err, 'error getting saved transaction state'); } }, config.retryDelay, + contracts, redis ); + + retryInterval.unref(); }; export const evatuateTransaction = async ( @@ -173,7 +171,10 @@ export const evatuateTransaction = async ( try { const payload = await txn.evaluate(...transactionArgs); - logger.debug({ payload }, 'Evaluate transaction response received'); + logger.debug( + { transactionId: txnId, payload: payload.toString() }, + 'Evaluate transaction response received' + ); return payload; } catch (err) { throw handleError(txnId, err); @@ -183,6 +184,7 @@ export const evatuateTransaction = async ( export const submitTransaction = async ( contract: Contract, redis: Redis, + mspId: string, transactionName: string, ...transactionArgs: string[] ): Promise => { @@ -195,7 +197,14 @@ export const submitTransaction = async ( try { // Store the transaction details and set the event handler in case there // are problems later with commiting the transaction - await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp); + await storeTransactionDetails( + redis, + txnId, + mspId, + txnState, + txnArgs, + timestamp + ); txn.setEventHandler(DefaultEventHandlerStrategies.NONE); await txn.submit(...transactionArgs); } catch (err) { @@ -212,6 +221,7 @@ export const submitTransaction = async ( // Unfortunately the chaincode samples do not use error codes, and the error // message text is not the same for each implementation +// TODO move to errors.ts? const handleError = (transactionId: string, err: Error): Error => { // This regex needs to match the following error messages: // "the asset %s already exists" @@ -266,40 +276,55 @@ const handleError = (transactionId: string, err: Error): Error => { return new TransactionError('Transaction error', transactionId); }; -export const retryTransaction = async ( +const retryTransaction = async ( contract: Contract, redis: Redis, - transactionId: string, - savedTransaction: Record + savedTransaction: TransactionDetails ): Promise => { - logger.debug('Retrying transaction %s', transactionId); + logger.debug('Retrying transaction %s', savedTransaction.transactionId); try { const transaction = contract.deserializeTransaction( - Buffer.from(savedTransaction.state) + savedTransaction.transactionState ); - const args: string[] = JSON.parse(savedTransaction.args); + const args: string[] = JSON.parse(savedTransaction.transactionArgs); - await transaction.submit(...args); - await clearTransactionDetails(redis, transactionId); + const payload = await transaction.submit(...args); + logger.debug( + { + transactionId: savedTransaction.transactionId, + payload: payload.toString(), + }, + 'Retry transaction response received' + ); + + await clearTransactionDetails(redis, savedTransaction.transactionId); } catch (err) { - if (isDuplicateTransaction(err)) { - logger.warn('Transaction %s has already been committed', transactionId); - await clearTransactionDetails(redis, transactionId); + if (isDuplicateTransactionError(err)) { + logger.warn( + 'Transaction %s has already been committed', + savedTransaction.transactionId + ); + await clearTransactionDetails(redis, savedTransaction.transactionId); } else { - // TODO check for retry limit and update timestamp logger.warn( err, 'Retry %d failed for transaction %s', savedTransaction.retries, - transactionId + savedTransaction.transactionId ); - await incrementRetryCount(redis, transactionId); + + if (savedTransaction.retries < config.maxRetryCount) { + await incrementRetryCount(redis, savedTransaction.transactionId); + } else { + await clearTransactionDetails(redis, savedTransaction.transactionId); + } } } }; -const isDuplicateTransaction = (error: { +// TODO move to errors.ts? +const isDuplicateTransactionError = (error: { errors: { endorsements: { details: string }[] }[]; }) => { // TODO this is horrible! Isn't it possible to check for TxValidationCode DUPLICATE_TXID somehow? diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 722079c5..b8b13d69 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -2,24 +2,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Contract, Network } from 'fabric-network'; +import { Network } from 'fabric-network'; import { Redis } from 'ioredis'; import * as config from './config'; -import { startRetryLoop, blockEventHandler } from './fabric'; +import { blockEventHandler } from './fabric'; import { logger } from './logger'; import { createServer } from './server'; async function main() { const app = await createServer(); - // TODO block listener and retry logic currently only handles a single org!!! - // TODO should these be initialised here? - const contract = app.get(config.mspIdOrg1).assetContract as Contract; + // TODO block listener currently only handles a single org!!! + // TODO should it be initialised here? const redis = app.get('redis') as Redis; const network = app.get('networkOrg1') as Network; - await network.addBlockListener(blockEventHandler(redis)); - startRetryLoop(contract, redis); app.listen(config.port, () => { logger.info('Express server started on port: %d', config.port); diff --git a/asset-transfer-basic/rest-api-typescript/src/logger.ts b/asset-transfer-basic/rest-api-typescript/src/logger.ts index fe53a01e..1f1cea83 100644 --- a/asset-transfer-basic/rest-api-typescript/src/logger.ts +++ b/asset-transfer-basic/rest-api-typescript/src/logger.ts @@ -1,3 +1,7 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + import pino from 'pino'; import * as config from './config'; diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts b/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts index 7d81cb99..8b4f291c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts @@ -1,75 +1,184 @@ -import IORedis from './__mocks__/IORedis'; +/* + * SPDX-License-Identifier: Apache-2.0 + */ + import * as config from './config'; -import { Redis } from 'ioredis'; +import IORedis, { Redis } from 'ioredis'; import { clearTransactionDetails, incrementRetryCount, storeTransactionDetails, + getTransactionDetails, + getRetryTransactionDetails, } from './redis'; -jest.mock('ioredis'); +jest.mock('ioredis', () => require('ioredis-mock/jest')); jest.mock('./config'); -const redisOptions = { - port: config.redisPort, - host: config.redisHost, - username: config.redisUsername, - password: config.redisPassword, -}; -const redis = new IORedis(redisOptions) as unknown as Redis; -describe('Testing increment retries ', () => { - const transactionId = +describe('Redis', () => { + let redis: Redis; + + const mockTransactionId = '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - it('Should increment retries for valid transction id', async () => { - await incrementRetryCount(redis, transactionId); - expect(redis.hincrby).toHaveBeenCalledTimes(1); + const mockKey = `txn:${mockTransactionId}`; + const mockMspId = 'Org1MSP'; + const mockState = Buffer.from( + `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${mockTransactionId}` + ); + const mockArgs = '["test111","red",400,"Jean",101]'; + const mockTimestamp = 1628078044362; + + const addMockTransationDetails = async (redis: Redis) => { + await redis + .multi() + .hset( + mockKey, + 'mspId', + mockMspId, + 'state', + mockState, + 'args', + mockArgs, + 'timestamp', + mockTimestamp, + 'retries', + '0' + ) + .zadd('index:txn:timestamp', mockTimestamp, mockTransactionId) + .exec(); + }; + + beforeEach(async () => { + const redisOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, + }; + + redis = new IORedis(redisOptions) as unknown as Redis; + }); + describe('storeTransactionDetails', () => { + it('stores transaction details as a hash', async () => { + await storeTransactionDetails( + redis, + mockTransactionId, + mockMspId, + mockState, + mockArgs, + mockTimestamp + ); + + const storedTransaction = await redis.hgetall(mockKey); + const expectedTransaction = { + mspId: mockMspId, + state: mockState, + args: mockArgs, + retries: '0', + timestamp: mockTimestamp.toString(), + }; + expect(storedTransaction).toStrictEqual(expectedTransaction); + }); + + it('adds the transaction ID to the sorted set timestamp index', async () => { + await storeTransactionDetails( + redis, + mockTransactionId, + mockMspId, + mockState, + mockArgs, + mockTimestamp + ); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([mockTransactionId]); + }); + + // TODO this seems to work for spying/mocking... + // jest.spyOn(redis, 'multi').mock... + // but haven't worked out how to spy on the hset, zadd, exec in that chain + // Ask Mark? + it.todo('handles an error from redis'); }); - it('Should not increment retries for empty transaction id ', async () => { - await incrementRetryCount(redis, ''); - expect(redis.hincrby).toHaveBeenCalledTimes(0); - }); -}); + describe('getTransactionDetails', () => { + it('gets the transaction details from a hash', async () => { + await addMockTransationDetails(redis); -describe('Testing storeTransactionDetails ', () => { - const args = '["test111","red",400,"Jean",101]'; - const timestamp = 1628078044362; - it('Should store details for valid transction Id', async () => { - const transactionId = - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; - await storeTransactionDetails( - redis, - transactionId, - Buffer.from(state), - args, - timestamp + const details = await getTransactionDetails(redis, mockTransactionId); + + expect(details).toStrictEqual({ + transactionId: mockTransactionId, + mspId: mockMspId, + transactionState: mockState, + transactionArgs: mockArgs, + retries: 0, + timestamp: mockTimestamp, + }); + }); + + it.todo('handles an error from redis'); + }); + + describe('getRetryTransactionDetails', () => { + it('gets the oldest transaction details from a hash', async () => { + await addMockTransationDetails(redis); + + const details = await getRetryTransactionDetails(redis); + + expect(details).toStrictEqual({ + transactionId: mockTransactionId, + mspId: mockMspId, + transactionState: mockState, + transactionArgs: mockArgs, + retries: 0, + timestamp: mockTimestamp, + }); + }); + + it('gets undefined if there are no transactions to retry', async () => { + const details = await getRetryTransactionDetails(redis); + + expect(details).toBeUndefined(); + }); + + it.todo('handles an error from redis'); + }); + + describe('clearTransactionDetails', () => { + it('removes the transaction details hash', async () => { + await addMockTransationDetails(redis); + + await clearTransactionDetails(redis, mockTransactionId); + + const storedTransaction = await redis.hgetall(mockKey); + expect(storedTransaction).not.toHaveProperty('state'); + }); + + it('removes the transaction ID from the sorted set timestamp index', async () => { + await addMockTransationDetails(redis); + + await clearTransactionDetails(redis, mockTransactionId); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([]); + }); + }); + + describe('incrementRetryCount', () => { + it('increments the retries value in the transction details hash', async () => { + await addMockTransationDetails(redis); + + await incrementRetryCount(redis, mockTransactionId); + + const retries = await redis.hget(mockKey, 'retries'); + expect(retries).toBe('1'); + }); + + it.todo( + 'updates the position of the transaction ID in the sorted set timestamp index' ); - expect(redis.hset).toHaveBeenCalledTimes(1); - expect(redis.zadd).toHaveBeenCalledTimes(1); - }); - it('Should not store details for empty transction Id', async () => { - const transactionId = ''; - const state = `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${transactionId}`; - await storeTransactionDetails( - redis, - transactionId, - Buffer.from(state), - args, - timestamp - ); - expect(redis.hset).toHaveBeenCalledTimes(0); - expect(redis.zadd).toHaveBeenCalledTimes(0); - }); -}); - -describe('Testing clearTransactionDetails ', () => { - it('Should clear details ', async () => { - const transactionId = - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - await clearTransactionDetails(redis, transactionId); - expect(redis.del).toHaveBeenCalledTimes(1); - expect(redis.zrem).toHaveBeenCalledTimes(1); + it.todo('handles an error from redis'); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.ts b/asset-transfer-basic/rest-api-typescript/src/redis.ts index c4e8b7c3..fc89fa9b 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.ts @@ -1,5 +1,12 @@ /* * SPDX-License-Identifier: Apache-2.0 + * + * This sample includes basic retry logic so it needs somewhere to store + * transaction details in case the app restarts for any reason, and Redis is + * just one of the options available + * + * Note: This implementation is not designed with multiple instances of the + * REST app in mind, which is likely to be required in a production environment */ import IORedis, { Redis, RedisOptions } from 'ioredis'; @@ -16,29 +23,44 @@ const redisOptions: RedisOptions = { export const redis = new IORedis(redisOptions); +export type TransactionDetails = { + transactionId: string; + mspId: string; + transactionState: Buffer; + transactionArgs: string; + timestamp: number; + retries: number; +}; + +/* + * Store enough information in order to resubmit a transaction + */ export const storeTransactionDetails = async ( redis: Redis, transactionId: string, + mspId: string, transactionState: Buffer, transactionArgs: string, timestamp: number ): Promise => { try { - if (transactionId.length === 0) { - throw new Error('Empty transaction Id found'); - } const key = `txn:${transactionId}`; logger.debug( - 'Storing transaction details. Key: %s State: %s Args: %s Timestamp: %d', - key, - transactionState, - transactionArgs, - timestamp + { + key, + mspId, + transactionState, + transactionArgs, + timestamp, + }, + 'Storing transaction details' ); await redis .multi() .hset( key, + 'mspId', + mspId, 'state', transactionState, 'args', @@ -51,14 +73,84 @@ export const storeTransactionDetails = async ( .zadd('index:txn:timestamp', timestamp, transactionId) .exec(); } catch (err) { + // TODO just log?! logger.error( - err, - 'Error storing transaction details. ID %s', + { err }, + 'Error storing details for transaction ID %s', transactionId ); } }; +/* + * Get the information required to resubmit a transaction + */ +export const getTransactionDetails = async ( + redis: Redis, + transactionId: string +): Promise => { + try { + const savedTransaction = await (redis as Redis).hgetall( + `txn:${transactionId}` + ); + logger.debug( + { transactionId: transactionId, state: savedTransaction }, + 'Got transaction details' + ); + + const transactionDetails = { + transactionId: transactionId, + mspId: savedTransaction.mspId, + transactionState: Buffer.from(savedTransaction.state), + transactionArgs: savedTransaction.args, + timestamp: parseInt(savedTransaction.timestamp), + retries: parseInt(savedTransaction.retries), + }; + return transactionDetails; + } catch (err) { + // TODO just log?! + logger.error( + { err }, + 'Error getting details for transaction ID %s', + transactionId + ); + } +}; + +/* + * Get the oldest transaction details + */ +export const getRetryTransactionDetails = async ( + redis: Redis +): Promise => { + try { + const transactionIds = await (redis as Redis).zrange( + 'index:txn:timestamp', + -1, + -1 + ); + + if (transactionIds.length > 0) { + const transactionId = transactionIds[0]; + + const savedTransaction = await getTransactionDetails( + redis, + transactionId + ); + return savedTransaction; + } + } catch (err) { + // TODO just log?! + logger.error( + { err }, + 'Error getting details for next transaction to retry' + ); + } +}; + +/* + * Delete transaction details + */ export const clearTransactionDetails = async ( redis: Redis, transactionId: string @@ -72,16 +164,20 @@ export const clearTransactionDetails = async ( .zrem('index:txn:timestamp', transactionId) .exec(); } catch (err) { + // TODO just log?! logger.error( - err, - 'Error remove saved transaction state for transaction ID %s', + { err }, + 'Error remove details for transaction ID %s', transactionId ); } }; -// TODO add getTransaction etc. helpers? +/* + * Increment the number of times the transaction has been retried + * TODO needs to update the timestamp and index as well + */ export const incrementRetryCount = async ( redis: Redis, transactionId: string @@ -89,11 +185,9 @@ export const incrementRetryCount = async ( const key = `txn:${transactionId}`; logger.debug('Incrementing retries fortransaction Key: %s', key); try { - if (transactionId.length === 0) { - throw new Error('Empty transaction Id found'); - } await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1); } catch (err) { + // TODO just log?! logger.error( err, 'Error incrementing retries for transaction ID %s', diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 14674a1c..e9e57e96 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -6,6 +6,7 @@ import helmet from 'helmet'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import express, { Application, NextFunction, Request, Response } from 'express'; import pinoMiddleware from 'pino-http'; +import { Contract } from 'fabric-network'; import { logger } from './logger'; import { assetsRouter } from './assets.router'; @@ -16,6 +17,7 @@ import { getNetwork, createGateway, createWallet, + startRetryLoop, } from './fabric'; import { redis } from './redis'; import * as config from './config'; @@ -91,6 +93,11 @@ export const createServer = async (): Promise => { const contractsOrg2 = await getContracts(networkOrg2); app.set(config.mspIdOrg2, contractsOrg2); + const assetContracts = new Map(); + assetContracts.set(config.mspIdOrg1, contractsOrg1.assetContract); + assetContracts.set(config.mspIdOrg2, contractsOrg2.assetContract); + startRetryLoop(assetContracts, redis); + app.set('redis', redis); app.use('/', healthRouter); diff --git a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts index 27f6438b..a91c2fc5 100644 --- a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts @@ -7,6 +7,7 @@ import { Contract } from 'fabric-network'; import { protos } from 'fabric-protos'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { Redis } from 'ioredis'; +import { getTransactionDetails } from './redis'; import { evatuateTransaction } from './fabric'; import { logger } from './logger'; import * as config from './config'; @@ -33,18 +34,14 @@ transactionsRouter.get( const redis = req.app.get('redis') as Redis; try { - const savedTransaction = await (redis as Redis).hgetall( - `txn:${transactionId}` - ); - logger.debug( - { transactionId: transactionId, state: savedTransaction }, - 'Saved transaction state' + const savedTransaction = await getTransactionDetails( + redis, + transactionId ); - if (savedTransaction.state) { + if (savedTransaction?.transactionState) { foundTransaction = true; - const retries = parseInt(savedTransaction.retries); - if (retries > 0) { + if (savedTransaction.retries > 0) { progress = 'RETRYING'; } else { progress = 'ACCEPTED'; From 9aec7ffd2a9a30a614d279c225251050dfa6e822 Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Fri, 10 Sep 2021 13:50:20 +0530 Subject: [PATCH 081/106] Clear Transaction when no contract found Signed-off-by: sapthasurendran --- .../rest-api-typescript/src/fabric.spec.ts | 12 ++++++++++++ .../rest-api-typescript/src/fabric.ts | 1 + 2 files changed, 13 insertions(+) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts index b74ddf7a..8f915849 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -280,6 +280,18 @@ describe('Fabric', () => { const index = await redis.zrange('index:txn:timestamp', 0, -1); expect(index).toStrictEqual([]); }); + + it('starts a retry loop which clears the saved details when no contract exist for the org', async () => { + addMockTransationDetails(redis); + mockContracts = new Map(); + startRetryLoop(mockContracts, redis); + jest.runOnlyPendingTimers(); + await flushPromises(); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([]); + }); + }); describe('evatuateTransaction', () => { diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 363f9c72..8a99d7cf 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -145,6 +145,7 @@ export const startRetryLoop = ( if (contract) { await retryTransaction(contract, redis, savedTransaction); } else { + clearTransactionDetails(redis,savedTransaction.transactionId) logger.error( 'No contract found for %s to retry transaction %s', savedTransaction.mspId, From e6738818e52bed41dbfa669f435102b9de744d41 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 9 Sep 2021 14:41:23 +0100 Subject: [PATCH 082/106] Update readmes Move usage instructions to the node sample directory and add overview/next steps to top level readme Signed-off-by: James Taylor --- README.md | 129 ++++-------------- .../rest-api-typescript/README.md | 126 +++++++++++++++++ 2 files changed, 152 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index 06f58ab8..076cf6c8 100644 --- a/README.md +++ b/README.md @@ -2,128 +2,51 @@ Prototype sample REST server to demonstrate good Fabric Node SDK practices for parts of [FAB-18511](https://jira.hyperledger.org/browse/FAB-18511) -The primary aim of this sample is to show how to write a long running client application using the Fabric Node SDK +The intention is to deliver the sample to the [asset-transfer-basic/rest-api-typescript directory of the fabric-samples repository](https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic) -The REST API is intended to work with the [basic asset transfer example](https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic) +See the [sample readme for usage intructions](asset-transfer-basic/rest-api-typescript/README.md) -To install the basic asset transfer chaincode on a local Fabric network, follow the [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/release-2.2/test_network.html) tutorial +## Overview -## Usage +The primary aim of this sample is to show how to write a long running client application using the Fabric Node SDK, i.e. without reconnecting for each transaction -**Note:** these instructions should work with the release-2.2 branch of `fabric-samples` but later versions require some changes +It should also show: -To build and start the sample REST server, you'll need to [download and install an LTS version of node](https://nodejs.org/en/download/) +- basic transaction retries +- long running event handling +- requests from multiple users -Clone this repository and change to the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory before running the following commands +## Next steps -Install dependencies +### Handling transaction errors -```shell -npm install -``` +Should transactions be retried _unless they fail_ with specific errors, e.g. duplicate transaction (the current implementation)? -Build the REST server +**or** -```shell -npm run build -``` +Should transactions be retried _when they fail_ with specific errors? -Create a `.env` file to configure the server for the test network (make sure TEST_NETWORK_HOME is set to the fully qualified `test-network` directory) +Also, transactions are currently only retried if they are successfully endorsed- does that seem reasonable? -```shell -TEST_NETWORK_HOME=$HOME/fabric-samples/test-network npm run generateEnv -``` +If the transaction failed because of MVCC_READ_CONFLICT, is a chance that it could pass when retrying? (Is MVCC_READ_CONFLICT an endorsement error?) -Start a Redis server +### Handling other errors -```shell -npm run start:redis -``` +Need to make sure it's clear what went wrong and fail properly it necessary, for example when starting without a redis instance -Start the sample REST server +### Finish off unit tests -```shell -npm run start:dev -``` +Coverage is looking much better now but there are a few more todos -### Docker image +### More comments -Alternatively, run the following commands in the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory to start the sample in a Docker container +Need to document what's going on and why, especially in the fabric.ts file! -Build the Docker image +### Feedback -```shell -docker build -t fabric-rest-sample . -``` +- More people trying out the sample (and ideally trying to break it a bit!) +- Code review to merge sample into fabric-samples -Create a `.env` file to configure the server for the test network (make sure `TEST_NETWORK_HOME` is set to the fully qualified `test-network` directory and `AS_LOCAL_HOST` is set to `false` so that the server works inside the Docker Compose network) +### Known problems -```shell -TEST_NETWORK_HOME=$HOME/fabric-samples/test-network AS_LOCAL_HOST=false npm run generateEnv -``` - -Start the sample REST server and Redis server - -```shell -docker-compose up -d -``` - -## REST API - -If everything went well, you can now make basic asset transfer REST calls! - -The examples below require a `SAMPLE_APIKEY` environment variable which must be set to an API key from the `.env` file created above. - -For example, to use the ORG1_APIKEY... - -``` -SAMPLE_APIKEY=$(grep ORG1_APIKEY .env | cut -d '=' -f 2-) -``` - -### Get all assets... - -```shell -curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets -``` - -### Check whether an asset exists... - -```shell -curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request OPTIONS http://localhost:3000/api/assets/asset7 -``` - -### Create an asset... - -```shell -curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets -``` - -### Read transaction status... - -```shell -curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/transactions/__transaction_id__ -``` - -### Read an asset... - -```shell -curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets/asset7 -``` - -### Update an asset... - -```shell -curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 -``` - -### Transfer an asset... - -```shell -curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 -``` - -### Delete an asset... - -```shell -curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request DELETE http://localhost:3000/api/assets/asset7 -``` +See [issues](https://github.com/hyperledgendary/fabric-rest-sample/issues) diff --git a/asset-transfer-basic/rest-api-typescript/README.md b/asset-transfer-basic/rest-api-typescript/README.md index d73efbdc..ea61b775 100644 --- a/asset-transfer-basic/rest-api-typescript/README.md +++ b/asset-transfer-basic/rest-api-typescript/README.md @@ -1,3 +1,129 @@ # Asset Transfer REST API Sample Prototype sample REST server to demonstrate good Fabric Node SDK practices + +The primary aim of this sample is to show how to write a long running client application using the Fabric Node SDK + +The REST API is intended to work with the [basic asset transfer example](https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic) + +To install the basic asset transfer chaincode on a local Fabric network, follow the [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/release-2.2/test_network.html) tutorial + +## Usage + +**Note:** these instructions should work with the release-2.2 branch of `fabric-samples` but later versions require some changes + +To build and start the sample REST server, you'll need to [download and install an LTS version of node](https://nodejs.org/en/download/) + +Clone this repository and change to the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory before running the following commands + +Install dependencies + +```shell +npm install +``` + +Build the REST server + +```shell +npm run build +``` + +Create a `.env` file to configure the server for the test network (make sure TEST_NETWORK_HOME is set to the fully qualified `test-network` directory) + +```shell +TEST_NETWORK_HOME=$HOME/fabric-samples/test-network npm run generateEnv +``` + +Start a Redis server + +```shell +npm run start:redis +``` + +Start the sample REST server + +```shell +npm run start:dev +``` + +### Docker image + +Alternatively, run the following commands in the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory to start the sample in a Docker container + +Build the Docker image + +```shell +docker build -t fabric-rest-sample . +``` + +Create a `.env` file to configure the server for the test network (make sure `TEST_NETWORK_HOME` is set to the fully qualified `test-network` directory and `AS_LOCAL_HOST` is set to `false` so that the server works inside the Docker Compose network) + +```shell +TEST_NETWORK_HOME=$HOME/fabric-samples/test-network AS_LOCAL_HOST=false npm run generateEnv +``` + +Start the sample REST server and Redis server + +```shell +docker-compose up -d +``` + +## REST API + +If everything went well, you can now make basic asset transfer REST calls! + +The examples below require a `SAMPLE_APIKEY` environment variable which must be set to an API key from the `.env` file created above. + +For example, to use the ORG1_APIKEY... + +``` +SAMPLE_APIKEY=$(grep ORG1_APIKEY .env | cut -d '=' -f 2-) +``` + +### Get all assets... + +```shell +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets +``` + +### Check whether an asset exists... + +```shell +curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request OPTIONS http://localhost:3000/api/assets/asset7 +``` + +### Create an asset... + +```shell +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets +``` + +### Read transaction status... + +```shell +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/transactions/__transaction_id__ +``` + +### Read an asset... + +```shell +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets/asset7 +``` + +### Update an asset... + +```shell +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 +``` + +### Transfer an asset... + +```shell +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 +``` + +### Delete an asset... + +```shell +curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request DELETE http://localhost:3000/api/assets/asset7 +``` From f1a9fea77d913b38de79d032815363de2cdcad03 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 10 Sep 2021 14:48:49 +0100 Subject: [PATCH 083/106] Fix lint errors Signed-off-by: James Taylor --- asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts | 1 - asset-transfer-basic/rest-api-typescript/src/fabric.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts index 8f915849..d04d8b6d 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -291,7 +291,6 @@ describe('Fabric', () => { const index = await redis.zrange('index:txn:timestamp', 0, -1); expect(index).toStrictEqual([]); }); - }); describe('evatuateTransaction', () => { diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 8a99d7cf..ea81b386 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -145,7 +145,7 @@ export const startRetryLoop = ( if (contract) { await retryTransaction(contract, redis, savedTransaction); } else { - clearTransactionDetails(redis,savedTransaction.transactionId) + clearTransactionDetails(redis, savedTransaction.transactionId); logger.error( 'No contract found for %s to retry transaction %s', savedTransaction.mspId, From 00a2dea50b0cba25ad638e8fa4fbbda60f94094f Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 10 Sep 2021 15:53:51 +0100 Subject: [PATCH 084/106] Add block event listener config Signed-off-by: James Taylor --- .../rest-api-typescript/src/config.spec.ts | 22 ++++ .../rest-api-typescript/src/config.ts | 19 ++- .../rest-api-typescript/src/fabric.spec.ts | 120 +++++++++++++----- .../rest-api-typescript/src/fabric.ts | 34 +++-- .../rest-api-typescript/src/index.ts | 9 -- .../rest-api-typescript/src/server.ts | 11 +- 6 files changed, 158 insertions(+), 57 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/config.spec.ts b/asset-transfer-basic/rest-api-typescript/src/config.spec.ts index cdfc6ecb..fdd5d91e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.spec.ts @@ -152,6 +152,28 @@ describe('Config values', () => { }); }); + describe('blockListenerOrg', () => { + it('defaults to "Org1"', () => { + const config = require('./config'); + expect(config.blockListenerOrg).toBe('Org1'); + }); + + it('can be configured using the "HLF_BLOCK_LISTENER_ORG" environment variable', () => { + process.env.HLF_BLOCK_LISTENER_ORG = 'Org2'; + const config = require('./config'); + expect(config.blockListenerOrg).toBe('Org2'); + }); + + it('throws an error when the "HLF_BLOCK_LISTENER_ORG" environment variable has an invalid value', () => { + process.env.HLF_BLOCK_LISTENER_ORG = 'Org3'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "HLF_BLOCK_LISTENER_ORG" should be one of [Org1, Org2]' + ); + }); + }); + describe('channelName', () => { it('defaults to "mychannel"', () => { const config = require('./config'); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index afc15aac..47c0f909 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -4,6 +4,9 @@ import * as env from 'env-var'; +export const ORG1 = 'Org1'; +export const ORG2 = 'Org2'; + /* * Log level for the REST server */ @@ -55,8 +58,8 @@ export const asLocalhost = env */ export const mspIdOrg1 = env .get('HLF_MSP_ID_ORG1') - .default('Org1MSP') - .example('Org1MSP') + .default(`${ORG1}MSP`) + .example(`${ORG1}MSP`) .asString(); /* @@ -64,10 +67,18 @@ export const mspIdOrg1 = env */ export const mspIdOrg2 = env .get('HLF_MSP_ID_ORG2') - .default('Org2MSP') - .example('Org2MSP') + .default(`${ORG2}MSP`) + .example(`${ORG2}MSP`) .asString(); +/* + * The block listener org + */ +export const blockListenerOrg = env + .get('HLF_BLOCK_LISTENER_ORG') + .default(ORG1) + .asEnum([ORG1, ORG2]); + /* * Name of the channel which the basic asset sample chaincode has been installed on */ diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts index d04d8b6d..f871c395 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -11,6 +11,7 @@ import { submitTransaction, getBlockHeight, startRetryLoop, + blockEventHandler, } from './fabric'; import * as config from './config'; @@ -22,11 +23,13 @@ import { } from './errors'; import { + BlockEvent, Contract, Gateway, GatewayOptions, Network, Transaction, + TransactionEvent, Wallet, } from 'fabric-network'; @@ -40,6 +43,36 @@ jest.mock('./config'); jest.mock('ioredis', () => require('ioredis-mock/jest')); describe('Fabric', () => { + const mockTransactionId = + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; + const mockKey = `txn:${mockTransactionId}`; + const mockMspId = 'Org1MSP'; + const mockState = Buffer.from( + `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${mockTransactionId}` + ); + const mockArgs = '["test111","red",400,"Jean",101]'; + const mockTimestamp = 1628078044362; + + const addMockTransationDetails = async (redis: Redis) => { + await redis + .multi() + .hset( + mockKey, + 'mspId', + mockMspId, + 'state', + mockState, + 'args', + mockArgs, + 'timestamp', + mockTimestamp, + 'retries', + '0' + ) + .zadd('index:txn:timestamp', mockTimestamp, mockTransactionId) + .exec(); + }; + describe('createWallet', () => { it('creates a wallet containing identities for both orgs', async () => { const wallet = await createWallet(); @@ -110,41 +143,11 @@ describe('Fabric', () => { let mockContract: MockProxy; let mockContracts: Map; - const mockTransactionId = - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - const mockKey = `txn:${mockTransactionId}`; - const mockMspId = 'Org1MSP'; - const mockState = Buffer.from( - `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${mockTransactionId}` - ); - const mockArgs = '["test111","red",400,"Jean",101]'; - const mockTimestamp = 1628078044362; - const flushPromises = () => { jest.useRealTimers(); return new Promise((resolve) => setImmediate(resolve)); }; - const addMockTransationDetails = async (redis: Redis) => { - await redis - .multi() - .hset( - mockKey, - 'mspId', - mockMspId, - 'state', - mockState, - 'args', - mockArgs, - 'timestamp', - mockTimestamp, - 'retries', - '0' - ) - .zadd('index:txn:timestamp', mockTimestamp, mockTransactionId) - .exec(); - }; - beforeEach(() => { const redisOptions = { port: config.redisPort, @@ -485,6 +488,63 @@ describe('Fabric', () => { }); }); + describe('blockEventHandler', () => { + let redis: Redis; + let mockIsValidGetter: jest.Mock; + let mockTransactionIdGetter: jest.Mock; + let mockTransactionEvent: MockProxy; + let mockBlockEvent: MockProxy; + + beforeEach(async () => { + const redisOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, + }; + + redis = new IORedis(redisOptions) as unknown as Redis; + addMockTransationDetails(redis); + + const baseMock = {}; + mockTransactionEvent = mock(baseMock); + mockIsValidGetter = jest.fn(); + Object.defineProperty(baseMock, 'isValid', { get: mockIsValidGetter }); + mockTransactionIdGetter = jest.fn(); + Object.defineProperty(baseMock, 'transactionId', { + get: mockTransactionIdGetter, + }); + + mockBlockEvent = mock(); + mockBlockEvent.getTransactionEvents.mockReturnValue([ + mockTransactionEvent, + ]); + }); + + it('clears saved details for valid transactions', async () => { + const blockListener = blockEventHandler(redis); + mockIsValidGetter.mockReturnValue(true); + mockTransactionIdGetter.mockReturnValue(mockTransactionId); + + await blockListener(mockBlockEvent); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([]); + }); + + it('does not clear saved details for invalid transactions', async () => { + const blockListener = blockEventHandler(redis); + mockIsValidGetter.mockReturnValue(false); + + await blockListener(mockBlockEvent); + + const index = await redis.zrange('index:txn:timestamp', 0, -1); + expect(index).toStrictEqual([ + '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95', + ]); + }); + }); + describe('getBlockHeight', () => { it('gets the current block height', async () => { const mockBlockchainInfoProto = diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index ea81b386..1e0844d2 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -344,23 +344,35 @@ const isDuplicateTransactionError = (error: { return false; }; +/* + * Block event listener to handle successful transactions + * + * Transaction details are saved before being submitted so that + * they can be retried, and this listener deletes those transaction + * details for any successful transactions + * + * Transactions can be submitted using one of two identities + * however one one of those identities is used to listen for + * block events + */ export const blockEventHandler = (redis: Redis): BlockListener => { - const blockListner = async (event: BlockEvent) => { - logger.debug('Block event received '); - const transEvents: Array = event.getTransactionEvents(); + const blockListener = async (event: BlockEvent) => { + logger.debug( + { blockNumber: event.blockNumber.toString() }, + 'Block event received' + ); + const transactionEvents: Array = + event.getTransactionEvents(); - for (const transEvent of transEvents) { - if (transEvent && transEvent.isValid) { - logger.debug( - 'Remove transation with txnId %s', - transEvent.transactionId - ); - await clearTransactionDetails(redis, transEvent.transactionId); + for (const event of transactionEvents) { + if (event && event.isValid) { + logger.debug('Remove transation with txnId %s', event.transactionId); + await clearTransactionDetails(redis, event.transactionId); } } }; - return blockListner; + return blockListener; }; export const getBlockHeight = async ( diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index b8b13d69..98f91ebc 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -2,22 +2,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Network } from 'fabric-network'; -import { Redis } from 'ioredis'; import * as config from './config'; -import { blockEventHandler } from './fabric'; import { logger } from './logger'; import { createServer } from './server'; async function main() { const app = await createServer(); - // TODO block listener currently only handles a single org!!! - // TODO should it be initialised here? - const redis = app.get('redis') as Redis; - const network = app.get('networkOrg1') as Network; - await network.addBlockListener(blockEventHandler(redis)); - app.listen(config.port, () => { logger.info('Express server started on port: %d', config.port); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index e9e57e96..e1f360aa 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -18,6 +18,7 @@ import { createGateway, createWallet, startRetryLoop, + blockEventHandler, } from './fabric'; import { redis } from './redis'; import * as config from './config'; @@ -81,9 +82,6 @@ export const createServer = async (): Promise => { const contractsOrg1 = await getContracts(networkOrg1); app.set(config.mspIdOrg1, contractsOrg1); - // TODO used for block listener, which needs fixing! - app.set('networkOrg1', networkOrg1); - const gatewayOrg2 = await createGateway( config.connectionProfileOrg2, config.mspIdOrg2, @@ -100,6 +98,13 @@ export const createServer = async (): Promise => { app.set('redis', redis); + logger.debug('Adding block listener to %s network', config.blockListenerOrg); + if (config.blockListenerOrg === config.ORG1) { + await networkOrg1.addBlockListener(blockEventHandler(redis)); + } else { + await networkOrg2.addBlockListener(blockEventHandler(redis)); + } + app.use('/', healthRouter); app.use('/api/assets', authenticateApiKey, assetsRouter); app.use('/api/transactions', authenticateApiKey, transactionsRouter); From fd269237d4debbee8428808d4bbae870a201db3c Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 13 Sep 2021 17:02:30 +0100 Subject: [PATCH 085/106] Add comments to fabric.ts Signed-off-by: James Taylor --- .../rest-api-typescript/src/fabric.ts | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 1e0844d2..acb81d5c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -104,11 +104,22 @@ export const createGateway = async ( return gateway; }; +/* + * Get the network which the asset transfer sample chaincode is running on + * + * In addion to getting the contract, the network will also be used to + * start a block event listener + */ export const getNetwork = async (gateway: Gateway): Promise => { const network = await gateway.getNetwork(config.channelName); return network; }; +/* + * Get the asset transfer sample contract and the qscc system contract + * + * The system contract is used for the liveness REST endpoint + */ export const getContracts = async ( network: Network ): Promise<{ assetContract: Contract; qsccContract: Contract }> => { @@ -117,6 +128,13 @@ export const getContracts = async ( return { assetContract, qsccContract }; }; +/* + * Starts a timer to retry transactions at regular intervals + * + * Note: there is check for whether the transaction has successfully completed + * since it could succeed between any check and the retry, so the additional + * transaction to get the status is unlikely to be worthwhile + */ export const startRetryLoop = ( contracts: Map, redis: Redis @@ -162,6 +180,9 @@ export const startRetryLoop = ( retryInterval.unref(); }; +/* + * Evaluate a transaction and handle any errors + */ export const evatuateTransaction = async ( contract: Contract, transactionName: string, @@ -182,6 +203,12 @@ export const evatuateTransaction = async ( } }; +/* + * Submit a transaction and handle any errors + * + * Transaction details are saved before being submitted so that they can be + * retried if any errors occur + */ export const submitTransaction = async ( contract: Contract, redis: Redis, @@ -277,6 +304,12 @@ const handleError = (transactionId: string, err: Error): Error => { return new TransactionError('Transaction error', transactionId); }; +/* + * Retry a transaction + * + * The saved transaction details include a retry count which is used to ensure + * failing transactions are not retried indefinitely + */ const retryTransaction = async ( contract: Contract, redis: Redis, @@ -347,13 +380,12 @@ const isDuplicateTransactionError = (error: { /* * Block event listener to handle successful transactions * - * Transaction details are saved before being submitted so that - * they can be retried, and this listener deletes those transaction - * details for any successful transactions + * Transaction details are saved before being submitted so that they can be + * retried, and this listener deletes those transaction details for any + * successful transactions * - * Transactions can be submitted using one of two identities - * however one one of those identities is used to listen for - * block events + * Transactions can be submitted using one of two identities however one one + * of those identities is used to listen for block events */ export const blockEventHandler = (redis: Redis): BlockListener => { const blockListener = async (event: BlockEvent) => { @@ -375,6 +407,12 @@ export const blockEventHandler = (redis: Redis): BlockListener => { return blockListener; }; +/* + * Get the current block height + * + * This example of using a system contract is used for the liveness REST + * endpoint + */ export const getBlockHeight = async ( qscc: Contract ): Promise => { From 0456a9e94c24ce987afb2dbfc74da08d71b679ac Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 14 Sep 2021 17:07:15 +0100 Subject: [PATCH 086/106] Move error related functions to errors.ts Signed-off-by: James Taylor --- .../rest-api-typescript/src/errors.spec.ts | 102 ++++++++++++++++++ .../rest-api-typescript/src/errors.ts | 90 ++++++++++++++++ .../rest-api-typescript/src/fabric.spec.ts | 42 +++----- .../rest-api-typescript/src/fabric.ts | 88 +-------------- 4 files changed, 211 insertions(+), 111 deletions(-) create mode 100644 asset-transfer-basic/rest-api-typescript/src/errors.spec.ts diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts b/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts new file mode 100644 index 00000000..a0813c90 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts @@ -0,0 +1,102 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + AssetExistsError, + AssetNotFoundError, + TransactionError, + TransactionNotFoundError, + handleError, + isDuplicateTransactionError, +} from './errors'; + +describe('Errors', () => { + describe('isDuplicateTransactionError', () => { + it('returns true for an error with duplicate transaction endorsement details', () => { + const mockDuplicateTransactionError = { + errors: [ + { + endorsements: [ + { + details: 'duplicate transaction found', + }, + ], + }, + ], + }; + + expect(isDuplicateTransactionError(mockDuplicateTransactionError)).toBe( + true + ); + }); + + it('returns false for an error without duplicate transaction endorsement details', () => { + const mockDuplicateTransactionError = { + errors: [ + { + endorsements: [ + { + details: 'mock endorsement details', + }, + ], + }, + ], + }; + + expect(isDuplicateTransactionError(mockDuplicateTransactionError)).toBe( + false + ); + }); + }); + + describe('handleError', () => { + it.each([ + 'the asset GOCHAINCODE already exists', + 'Asset JAVACHAINCODE already exists', + 'The asset JSCHAINCODE already exists', + ])( + 'returns an AssetExistsError for errors with an asset already exists message: %s', + (msg) => { + expect(handleError('txn1', new Error(msg))).toStrictEqual( + new AssetExistsError(msg, 'txn1') + ); + } + ); + + it.each([ + 'the asset GOCHAINCODE does not exist', + 'Asset JAVACHAINCODE does not exist', + 'The asset JSCHAINCODE does not exist', + ])( + 'returns an AssetNotFoundError for errors with an asset does not exist message: %s', + (msg) => { + expect(handleError('txn1', new Error(msg))).toStrictEqual( + new AssetNotFoundError(msg, 'txn1') + ); + } + ); + + it('returns a TransactionNotFoundError for errors with a transaction not found message', () => { + expect( + handleError( + 'txn1', + new Error( + 'Failed to get transaction with id txn, error Entry not found in index' + ) + ) + ).toStrictEqual( + new TransactionNotFoundError( + 'Failed to get transaction with id txn, error Entry not found in index', + 'txn1' + ) + ); + }); + + it('returns a TransactionError for errors with other messages', () => { + expect(handleError('txn1', new Error('MOCK ERROR'))).toStrictEqual( + new TransactionError('Transaction error', 'txn1') + ); + }); + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.ts b/asset-transfer-basic/rest-api-typescript/src/errors.ts index 21692ac1..5a1fde2e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/errors.ts +++ b/asset-transfer-basic/rest-api-typescript/src/errors.ts @@ -2,6 +2,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { logger } from './logger'; + export class TransactionError extends Error { transactionId: string; @@ -43,3 +45,91 @@ export class AssetNotFoundError extends TransactionError { this.name = 'AssetNotFoundError'; } } + +/* + * Checks whether an error was caused by a duplicate transaction. + * + * Checking error strings like this is not ideal, unfortunately it appears to + * be the only option. In this case it would be better to check for the + * DUPLICATE_TXID TxValidationCode somehow but that does not seem to be + * possible. + */ +export const isDuplicateTransactionError = (error: { + errors: { endorsements: { details: string }[] }[]; +}): boolean => { + try { + const isDuplicateTxn = error?.errors?.some((err) => + err?.endorsements?.some((endorsement) => + endorsement?.details?.startsWith('duplicate transaction found') + ) + ); + + return isDuplicateTxn; + } catch (err) { + logger.warn(err, 'Error checking for duplicate transaction'); + } + + return false; +}; + +/* + * Handles errors from evaluating and submitting transactions. + * + * As with duplicate transaction errors, checking error strings like this is + * not ideal. Unfortunately the chaincode samples do not use error codes so + * again it's the only option. The error message text is not even the same for + * the Go, Java, and Javascript implementations of the chaincode! + */ +export const handleError = (transactionId: string, err: Error): Error => { + // This regex needs to match the following error messages: + // "the asset %s already exists" + // "The asset ${id} already exists" + // "Asset %s already exists" + const assetAlreadyExistsRegex = /([tT]he )?[aA]sset \w* already exists/g; + const assetAlreadyExistsMatch = err.message.match(assetAlreadyExistsRegex); + logger.debug( + { message: err.message, result: assetAlreadyExistsMatch }, + 'Checking for asset already exists message' + ); + if (assetAlreadyExistsMatch) { + return new AssetExistsError(assetAlreadyExistsMatch[0], transactionId); + } + + // This regex needs to match the following error messages: + // "the asset %s does not exist" + // "The asset ${id} does not exist" + // "Asset %s does not exist" + const assetDoesNotExistRegex = /([tT]he )?[aA]sset \w* does not exist/g; + const assetDoesNotExistMatch = err.message.match(assetDoesNotExistRegex); + logger.debug( + { message: err.message, result: assetDoesNotExistMatch }, + 'Checking for asset does not exist message' + ); + if (assetDoesNotExistMatch) { + return new AssetNotFoundError(assetDoesNotExistMatch[0], transactionId); + } + + // This regex needs to match the following error messages: + // "Failed to get transaction with id %s, error Entry not found in index" + const transactionDoesNotExistRegex = + /Failed to get transaction with id [^,]*, error Entry not found in index/g; + const transactionDoesNotExistMatch = err.message.match( + transactionDoesNotExistRegex + ); + logger.debug( + { message: err.message, result: transactionDoesNotExistMatch }, + 'Checking for transaction does not exist message' + ); + if (transactionDoesNotExistMatch) { + return new TransactionNotFoundError( + transactionDoesNotExistMatch[0], + transactionId + ); + } + + logger.error( + { transactionId: transactionId, error: err }, + 'Unhandled transaction error' + ); + return new TransactionError('Transaction error', transactionId); +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts index f871c395..a551dac9 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -320,35 +320,25 @@ describe('Fabric', () => { expect(result.toString()).toBe(mockPayload.toString()); }); - it.each([ - 'the asset GOCHAINCODE already exists', - 'Asset JAVACHAINCODE already exists', - 'The asset JSCHAINCODE already exists', - ])( - 'throws an AssetExistsError an asset already exists error occurs: %s', - async (msg) => { - mockTransaction.evaluate.mockRejectedValue(new Error(msg)); + it('throws an AssetExistsError an asset already exists error occurs', async () => { + mockTransaction.evaluate.mockRejectedValue( + new Error('The asset JSCHAINCODE already exists') + ); - await expect(async () => { - await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); - }).rejects.toThrow(AssetExistsError); - } - ); + await expect(async () => { + await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); + }).rejects.toThrow(AssetExistsError); + }); - it.each([ - 'the asset GOCHAINCODE does not exist', - 'Asset JAVACHAINCODE does not exist', - 'The asset JSCHAINCODE does not exist', - ])( - 'throws an AssetNotFoundError if an asset does not exist error occurs: %s', - async (msg) => { - mockTransaction.evaluate.mockRejectedValue(new Error(msg)); + it('throws an AssetNotFoundError if an asset does not exist error occurs', async () => { + mockTransaction.evaluate.mockRejectedValue( + new Error('The asset JSCHAINCODE does not exist') + ); - await expect(async () => { - await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); - }).rejects.toThrow(AssetNotFoundError); - } - ); + await expect(async () => { + await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); + }).rejects.toThrow(AssetNotFoundError); + }); it('throws a TransactionNotFoundError if a transaction not found error occurs', async () => { mockTransaction.evaluate.mockRejectedValue( diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index acb81d5c..aa8586ea 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -25,12 +25,7 @@ import { incrementRetryCount, TransactionDetails, } from './redis'; -import { - AssetExistsError, - AssetNotFoundError, - TransactionError, - TransactionNotFoundError, -} from './errors'; +import { handleError, isDuplicateTransactionError } from './errors'; import protos from 'fabric-protos'; /* @@ -247,63 +242,6 @@ export const submitTransaction = async ( return txnId; }; -// Unfortunately the chaincode samples do not use error codes, and the error -// message text is not the same for each implementation -// TODO move to errors.ts? -const handleError = (transactionId: string, err: Error): Error => { - // This regex needs to match the following error messages: - // "the asset %s already exists" - // "The asset ${id} already exists" - // "Asset %s already exists" - const assetAlreadyExistsRegex = /([tT]he )?[aA]sset \w* already exists/g; - const assetAlreadyExistsMatch = err.message.match(assetAlreadyExistsRegex); - logger.debug( - { message: err.message, result: assetAlreadyExistsMatch }, - 'Checking for asset already exists message' - ); - if (assetAlreadyExistsMatch) { - return new AssetExistsError(assetAlreadyExistsMatch[0], transactionId); - } - - // This regex needs to match the following error messages: - // "the asset %s does not exist" - // "The asset ${id} does not exist" - // "Asset %s does not exist" - const assetDoesNotExistRegex = /([tT]he )?[aA]sset \w* does not exist/g; - const assetDoesNotExistMatch = err.message.match(assetDoesNotExistRegex); - logger.debug( - { message: err.message, result: assetDoesNotExistMatch }, - 'Checking for asset does not exist message' - ); - if (assetDoesNotExistMatch) { - return new AssetNotFoundError(assetDoesNotExistMatch[0], transactionId); - } - - // This regex needs to match the following error messages: - // "Failed to get transaction with id %s, error Entry not found in index" - const transactionDoesNotExistRegex = - /Failed to get transaction with id [^,]*, error Entry not found in index/g; - const transactionDoesNotExistMatch = err.message.match( - transactionDoesNotExistRegex - ); - logger.debug( - { message: err.message, result: transactionDoesNotExistMatch }, - 'Checking for transaction does not exist message' - ); - if (transactionDoesNotExistMatch) { - return new TransactionNotFoundError( - transactionDoesNotExistMatch[0], - transactionId - ); - } - - logger.error( - { transactionId: transactionId, error: err }, - 'Unhandled transaction error' - ); - return new TransactionError('Transaction error', transactionId); -}; - /* * Retry a transaction * @@ -357,26 +295,6 @@ const retryTransaction = async ( } }; -// TODO move to errors.ts? -const isDuplicateTransactionError = (error: { - errors: { endorsements: { details: string }[] }[]; -}) => { - // TODO this is horrible! Isn't it possible to check for TxValidationCode DUPLICATE_TXID somehow? - try { - const isDuplicateTxn = error?.errors?.some((err) => - err?.endorsements?.some((endorsement) => - endorsement?.details?.startsWith('duplicate transaction found') - ) - ); - - return isDuplicateTxn; - } catch (err) { - logger.warn(err, 'Error checking for duplicate transaction'); - } - - return false; -}; - /* * Block event listener to handle successful transactions * @@ -409,9 +327,9 @@ export const blockEventHandler = (redis: Redis): BlockListener => { /* * Get the current block height - * + * * This example of using a system contract is used for the liveness REST - * endpoint + * endpoint */ export const getBlockHeight = async ( qscc: Contract From 211523eb9faf292372cb29c0c874d488ed0fc4b5 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Thu, 30 Sep 2021 10:18:16 -0400 Subject: [PATCH 087/106] Set up a GitHub action to publish the image to ghcr.io/hyperledgendary/fabric-rest-sample Signed-off-by: Josh Kneubuhl --- .github/workflows/publish.yaml | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/publish.yaml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 00000000..0068013a --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,54 @@ +name: fabric-rest-sample + +on: + push: + # Publish `main` as Docker `latest` image. + branches: + - main + + # Publish `v1.2.3` tags as releases. + tags: + - v* + + # Run tests for any PRs. + pull_request: + +env: + IMAGE_NAME: fabric-rest-sample + SOURCE_FOLDER: asset-transfer-basic/rest-api-typescript + +jobs: + # Push image to GitHub Packages. + # See also https://docs.docker.com/docker-hub/builds/ + push: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + + steps: + - uses: actions/checkout@v2 + + - name: Build image + run: docker build $SOURCE_FOLDER --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" + + - name: Log in to registry + # This is where you will update the PAT to GITHUB_TOKEN + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Push image + run: | + IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME + + # Change all uppercase to lowercase + IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') + # Strip git ref prefix from version + VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') + # Strip "v" prefix from tag name + [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') + # Use Docker `latest` tag convention + [ "$VERSION" == "main" ] && VERSION=latest + echo IMAGE_ID=$IMAGE_ID + echo VERSION=$VERSION + docker tag $IMAGE_NAME $IMAGE_ID:$VERSION + docker push $IMAGE_ID:$VERSION \ No newline at end of file From 3e49e92703fa3cb48163e59db6f9d1e6b05ca739 Mon Sep 17 00:00:00 2001 From: Josh Kneubuhl Date: Thu, 30 Sep 2021 10:21:02 -0400 Subject: [PATCH 088/106] wrong Dockerfile path - try again Signed-off-by: Josh Kneubuhl --- .github/workflows/publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 0068013a..d24714b2 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@v2 - name: Build image - run: docker build $SOURCE_FOLDER --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" + run: docker build --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" $SOURCE_FOLDER - name: Log in to registry # This is where you will update the PAT to GITHUB_TOKEN From ad3fd7e832f9dd349ec2fd2bcdfc29e74a6296e1 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 22 Sep 2021 19:27:38 +0100 Subject: [PATCH 089/106] Update retry logic Previously transactions were only retried after being successfully endorsed, and always with the same transaction ID Transactions will now be added to a queue for processing and will also be retried if endorsement fails (with a different transaction id for invalid transactions) Signed-off-by: James Taylor --- .../rest-api-typescript/README.md | 57 ++- .../rest-api-typescript/demo.http | 5 + .../rest-api-typescript/package-lock.json | 130 ++++- .../rest-api-typescript/package.json | 5 +- .../src/__mocks__/fabric-network.ts | 178 ------- .../src/__tests__/api.test.ts | 298 +++++++---- .../rest-api-typescript/src/assets.router.ts | 131 ++--- .../rest-api-typescript/src/config.spec.ts | 168 +++++-- .../rest-api-typescript/src/config.ts | 70 ++- .../rest-api-typescript/src/errors.spec.ts | 143 +++++- .../rest-api-typescript/src/errors.ts | 213 +++++--- .../rest-api-typescript/src/fabric.spec.ts | 472 +++++++----------- .../rest-api-typescript/src/fabric.ts | 342 ++++++------- .../rest-api-typescript/src/health.router.ts | 23 +- .../rest-api-typescript/src/index.ts | 82 ++- .../rest-api-typescript/src/jobs.router.ts | 41 ++ .../rest-api-typescript/src/jobs.spec.ts | 155 ++++++ .../rest-api-typescript/src/jobs.ts | 216 ++++++++ .../rest-api-typescript/src/redis.spec.ts | 188 +------ .../rest-api-typescript/src/redis.ts | 208 ++------ .../rest-api-typescript/src/server.ts | 68 +-- .../src/transactions.router.ts | 85 +--- 22 files changed, 1826 insertions(+), 1452 deletions(-) delete mode 100644 asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/jobs.router.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts create mode 100644 asset-transfer-basic/rest-api-typescript/src/jobs.ts diff --git a/asset-transfer-basic/rest-api-typescript/README.md b/asset-transfer-basic/rest-api-typescript/README.md index ea61b775..b5191620 100644 --- a/asset-transfer-basic/rest-api-typescript/README.md +++ b/asset-transfer-basic/rest-api-typescript/README.md @@ -8,6 +8,21 @@ The REST API is intended to work with the [basic asset transfer example](https:/ To install the basic asset transfer chaincode on a local Fabric network, follow the [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/release-2.2/test_network.html) tutorial +## Overview + +The sample creates two long lived connections to a Fabric network in order to submit and evaluate transactions using two different identities + +To ensure requests respond quickly enough to avoid timeouts, all submit transactions are queued for processing and will be retried if they fail + +Submit transactions are retried if they fail with any error, except for errors from the smart contract, or duplicate transaction errors + +Alternatively you might prefer to modify the sample to only retry transactions which fail with specific errors instead, for example: +- MVCC_READ_CONFLICT +- PHANTOM_READ_CONFLICT +- ENDORSEMENT_POLICY_FAILURE +- CHAINCODE_VERSION_CONFLICT +- EXPIRED_CHAINCODE + ## Usage **Note:** these instructions should work with the release-2.2 branch of `fabric-samples` but later versions require some changes @@ -70,7 +85,7 @@ docker-compose up -d ## REST API -If everything went well, you can now make basic asset transfer REST calls! +If everything went well, you can now open a new terminal and try out some basic asset transfer REST calls! The examples below require a `SAMPLE_APIKEY` environment variable which must be set to an API key from the `.env` file created above. @@ -86,6 +101,12 @@ SAMPLE_APIKEY=$(grep ORG1_APIKEY .env | cut -d '=' -f 2-) curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets ``` +You should see all the available assets, for example + +``` +[{"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}] +``` + ### Check whether an asset exists... ```shell @@ -98,18 +119,52 @@ curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request OPTIONS http://l curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets ``` +The response should include a `jobId` which you can use to check the job status in next step + +``` +{"status":"Accepted","jobId":"1","timestamp":"2021-10-22T16:27:09.426Z"} +``` + +### Read job status... + +```shell +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/jobs/__job_id__ +``` + +The response should include a list of `transactionIds` which you can use to check the transaction status in next step, for example + +``` +{"jobId":"1","transactionIds":["1dd35c2e5d840fec1dccc6e8cfce886c660c103de3e7b93dd774d04f39eef82a"],"transactionPayload":""} +``` + +There may be more transaction IDs if the job was retried + ### Read transaction status... ```shell curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/transactions/__transaction_id__ ``` +The response will show the validation code of the transaction, for example + +``` +{"transactionId":"1dd35c2e5d840fec1dccc6e8cfce886c660c103de3e7b93dd774d04f39eef82a","validationCode":"VALID"} +``` + +Alternatively, you will get a 404 not found response if the transaction was not committed + ### Read an asset... ```shell curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets/asset7 ``` +You should see the newly created asset, for example + +``` +{"AppraisedValue":101,"Color":"red","ID":"asset7","Owner":"Jean","Size":42} +``` + ### Update an asset... ```shell diff --git a/asset-transfer-basic/rest-api-typescript/demo.http b/asset-transfer-basic/rest-api-typescript/demo.http index 163c7632..13ebfe99 100644 --- a/asset-transfer-basic/rest-api-typescript/demo.http +++ b/asset-transfer-basic/rest-api-typescript/demo.http @@ -40,6 +40,11 @@ X-Api-Key: {{api-key}} "appraisedValue": 101 } +### Read job status + +GET {{apiUrl}}/jobs/__job_id__ HTTP/1.1 +X-Api-Key: {{api-key}} + ### Read transaction status GET {{apiUrl}}/transactions/__transaction_id__ HTTP/1.1 diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index e7e35369..c56206e9 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -1955,6 +1955,67 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, + "bullmq": { + "version": "1.47.2", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.47.2.tgz", + "integrity": "sha512-IMzWjXdw6B5RSqPyEiOvoA0efjfTFx2DuB1N+z3T2wYcOVLIcIFybbFjhqVn9Sv/Zb5l6TpuFiU52P+C+/DpNA==", + "requires": { + "@types/ioredis": "^4.27.0", + "cron-parser": "^2.7.3", + "get-port": "^5.0.0", + "ioredis": "^4.27.8", + "lodash": "^4.17.21", + "semver": "^6.3.0", + "tslib": "^1.10.0", + "uuid": "^8.3.2" + }, + "dependencies": { + "@types/ioredis": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.27.4.tgz", + "integrity": "sha512-uTAA/woL//GxXQI1e9FuUoDZCpP8yn5LXQdea1IEFyLtb8GP2w3HfOE+SqglF6QSAp/3cZLWzrMhHqWSYI3bfg==", + "requires": { + "@types/node": "*" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ioredis": { + "version": "4.27.9", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.27.9.tgz", + "integrity": "sha512-hAwrx9F+OQ0uIvaJefuS3UTqW+ByOLyLIV+j0EH8ClNVxvFyH9Vmb08hCL4yje6mDYT5zMquShhypkd50RRzkg==", + "requires": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -2179,6 +2240,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cron-parser": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.18.0.tgz", + "integrity": "sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==", + "requires": { + "is-nan": "^1.3.0", + "moment-timezone": "^0.5.31" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2267,6 +2337,14 @@ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3105,6 +3183,11 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -3360,15 +3443,16 @@ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" }, "ioredis": { - "version": "4.27.6", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.27.6.tgz", - "integrity": "sha512-6W3ZHMbpCa8ByMyC1LJGOi7P2WiOKP9B3resoZOVLDhi+6dDBOW+KNsRq3yI36Hmnb2sifCxHX+YSarTeXh48A==", + "version": "4.27.9", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.27.9.tgz", + "integrity": "sha512-hAwrx9F+OQ0uIvaJefuS3UTqW+ByOLyLIV+j0EH8ClNVxvFyH9Vmb08hCL4yje6mDYT5zMquShhypkd50RRzkg==", "requires": { "cluster-key-slot": "^1.1.0", "debug": "^4.3.1", "denque": "^1.1.0", "lodash.defaults": "^4.2.0", "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", "p-map": "^2.1.0", "redis-commands": "1.7.0", "redis-errors": "^1.2.0", @@ -3452,6 +3536,15 @@ "is-extglob": "^2.1.1" } }, + "is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4997,6 +5090,11 @@ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5147,6 +5245,19 @@ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "moment-timezone": { + "version": "0.5.33", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", + "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "requires": { + "moment": ">= 2.9.0" + } + }, "mri": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", @@ -5252,6 +5363,11 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -6378,8 +6494,7 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsutils": { "version": "3.21.0", @@ -6473,6 +6588,11 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index 815f9e19..6a9317ff 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -4,6 +4,7 @@ "description": "Asset Transfer Basic REST API implemented in TypeScript", "main": "dist/index.js", "dependencies": { + "bullmq": "^1.47.2", "dotenv": "^10.0.0", "env-var": "^7.0.1", "express": "^4.17.1", @@ -11,7 +12,7 @@ "fabric-network": "^2.2.8", "helmet": "^4.6.0", "http-status-codes": "^2.1.4", - "ioredis": "^4.27.6", + "ioredis": "^4.27.8", "passport": "^0.4.1", "passport-headerapikey": "^1.2.2", "pino": "^6.11.3", @@ -53,7 +54,7 @@ "start": "node --require source-map-support/register ./dist", "start:dotenv": "node --require source-map-support/register --require dotenv/config ./dist", "start:dev": "node --require source-map-support/register --require dotenv/config ./dist | pino-pretty", - "start:redis": "docker run -p 6379:6379 --name fabric-sample-redis -d redis", + "start:redis": "docker run -p 6379:6379 --name fabric-sample-redis -d redis --maxmemory-policy noeviction", "test": "jest" }, "author": "Hyperledger", diff --git a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts b/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts deleted file mode 100644 index 4f58ae24..00000000 --- a/asset-transfer-basic/rest-api-typescript/src/__mocks__/fabric-network.ts +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -import { mock } from 'jest-mock-extended'; -import { Contract, Network, Transaction } from 'fabric-network'; -import { mocked } from 'ts-jest/utils'; -import * as fabricProtos from 'fabric-protos'; - -const actualFabricNetwork = jest.requireActual('fabric-network'); -const Wallet = actualFabricNetwork.Wallet; -const Wallets = actualFabricNetwork.Wallets; - -const mockAsset1 = { - ID: 'asset1', - Color: 'blue', - Size: 5, - Owner: 'Tomoko', - AppraisedValue: 300, -}; -const mockAsset1Buffer = Buffer.from(JSON.stringify(mockAsset1)); - -const mockAsset2 = { - ID: 'asset2', - Color: 'red', - Size: 5, - Owner: 'Brad', - AppraisedValue: 400, -}; - -const mockAllAssetsBuffer = Buffer.from( - JSON.stringify([mockAsset1, mockAsset2]) -); - -const mockBlockchainInfoProto = fabricProtos.common.BlockchainInfo.create(); -mockBlockchainInfoProto.height = 42; -const mockBlockchainInfoBuffer = Buffer.from( - fabricProtos.common.BlockchainInfo.encode(mockBlockchainInfoProto).finish() -); - -const processedTransactionProto = - fabricProtos.protos.ProcessedTransaction.create(); -processedTransactionProto.validationCode = - fabricProtos.protos.TxValidationCode.VALID; -const processedTransactionBuffer = Buffer.from( - fabricProtos.protos.ProcessedTransaction.encode( - processedTransactionProto - ).finish() -); - -type FabricNetworkModule = jest.Mocked; - -const { - DefaultEventHandlerStrategies, - DefaultQueryHandlerStrategies, - Gateway, -}: FabricNetworkModule = jest.createMockFromModule('fabric-network'); - -const mockAssetExistsTransaction = mock(); -mockAssetExistsTransaction.evaluate - .calledWith('asset1') - .mockResolvedValue(Buffer.from('true')); -mockAssetExistsTransaction.evaluate - .calledWith('asset3') - .mockResolvedValue(Buffer.from('false')); - -const mockReadAssetTransaction = mock(); -mockReadAssetTransaction.evaluate - .calledWith('asset1') - .mockResolvedValue(mockAsset1Buffer); -mockReadAssetTransaction.evaluate - .calledWith('asset3') - .mockRejectedValue(new Error('the asset asset3 does not exist')); - -const mockCreateAssetTransaction = mock(); -mockCreateAssetTransaction.getTransactionId.mockReturnValue('txn1'); -mockCreateAssetTransaction.submit - .calledWith('asset1') - .mockRejectedValue( - new Error( - 'No valid responses from any peers. Errors:\n peer=peer0.org1.example.com:7051, status=500, message=the asset asset1 already exists\n peer=peer0.org2.example.com:9051, status=500, message=the asset asset3 already exists' - ) - ); - -// NOTE: only the second mocked GetAllAssets with return no assets -// TODO find a better alternative so that test order does not matter -const mockGetAllAssetsTransaction = mock(); -mockGetAllAssetsTransaction.evaluate - .mockResolvedValueOnce(Buffer.from('')) - .mockResolvedValueOnce(mockAllAssetsBuffer); - -const mockUpdateAssetTransaction = mock(); -mockUpdateAssetTransaction.getTransactionId.mockReturnValue('txn1'); -mockUpdateAssetTransaction.submit - .calledWith('asset3') - .mockRejectedValue( - new Error( - 'No valid responses from any peers. Errors:\n peer=peer0.org1.example.com:7051, status=500, message=the asset asset3 does not exist\n peer=peer0.org2.example.com:9051, status=500, message=the asset asset3 does not exist' - ) - ); - -const mockTransferAssetTransaction = mock(); -mockTransferAssetTransaction.getTransactionId.mockReturnValue('txn1'); -mockTransferAssetTransaction.submit - .calledWith('asset3') - .mockRejectedValue( - new Error( - 'No valid responses from any peers. Errors:\n peer=peer0.org1.example.com:7051, status=500, message=the asset asset3 does not exist\n peer=peer0.org2.example.com:9051, status=500, message=the asset asset3 does not exist' - ) - ); - -const mockDeleteAssetTransaction = mock(); -mockDeleteAssetTransaction.getTransactionId.mockReturnValue('txn1'); -mockDeleteAssetTransaction.submit - .calledWith('asset3') - .mockRejectedValue( - new Error( - 'No valid responses from any peers. Errors:\n peer=peer0.org1.example.com:7051, status=500, message=the asset asset3 does not exist\n peer=peer0.org2.example.com:9051, status=500, message=the asset asset3 does not exist' - ) - ); - -const mockBasicContract = mock(); -mockBasicContract.createTransaction - .calledWith('AssetExists') - .mockReturnValue(mockAssetExistsTransaction); -mockBasicContract.createTransaction - .calledWith('ReadAsset') - .mockReturnValue(mockReadAssetTransaction); -mockBasicContract.createTransaction - .calledWith('CreateAsset') - .mockReturnValue(mockCreateAssetTransaction); -mockBasicContract.createTransaction - .calledWith('GetAllAssets') - .mockReturnValue(mockGetAllAssetsTransaction); -mockBasicContract.createTransaction - .calledWith('UpdateAsset') - .mockReturnValue(mockUpdateAssetTransaction); -mockBasicContract.createTransaction - .calledWith('TransferAsset') - .mockReturnValue(mockTransferAssetTransaction); -mockBasicContract.createTransaction - .calledWith('DeleteAsset') - .mockReturnValue(mockDeleteAssetTransaction); - -const mockGetTransactionByIDTransaction = mock(); -mockGetTransactionByIDTransaction.evaluate - .calledWith('mychannel', 'txn2') - .mockResolvedValue(processedTransactionBuffer); -mockGetTransactionByIDTransaction.evaluate - .calledWith('mychannel', 'txn3') - .mockRejectedValue( - new Error( - 'Failed to get transaction with id txn3, error Entry not found in index' - ) - ); - -const mockSystemContract = mock(); -mockSystemContract.evaluateTransaction - .calledWith('GetChainInfo') - .mockResolvedValue(mockBlockchainInfoBuffer); -mockSystemContract.createTransaction - .calledWith('GetTransactionByID') - .mockReturnValue(mockGetTransactionByIDTransaction); - -const mockNetwork = mock(); -mockNetwork.getContract.calledWith('basic').mockReturnValue(mockBasicContract); -mockNetwork.getContract.calledWith('qscc').mockReturnValue(mockSystemContract); - -mocked(Gateway.prototype.getNetwork).mockResolvedValue(mockNetwork); - -export { - DefaultEventHandlerStrategies, - DefaultQueryHandlerStrategies, - Contract, - Gateway, - Wallet, - Wallets, -}; diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts index 5b065426..06d29dba 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts @@ -2,20 +2,53 @@ * SPDX-License-Identifier: Apache-2.0 */ -jest.mock('fabric-network'); -jest.mock('ioredis', () => require('ioredis-mock/jest')); - -import { createServer } from '../server'; +import { Job, Queue } from 'bullmq'; import { Application } from 'express'; +import { Contract, Transaction } from 'fabric-network'; +import * as fabricProtos from 'fabric-protos'; +import { mock, MockProxy } from 'jest-mock-extended'; +import { mocked } from 'ts-jest/utils'; import request from 'supertest'; +import * as config from '../config'; +import { createServer } from '../server'; + +jest.mock('../config'); +jest.mock('bullmq'); + +const mockAsset1 = { + ID: 'asset1', + Color: 'blue', + Size: 5, + Owner: 'Tomoko', + AppraisedValue: 300, +}; +const mockAsset1Buffer = Buffer.from(JSON.stringify(mockAsset1)); + +const mockAsset2 = { + ID: 'asset2', + Color: 'red', + Size: 5, + Owner: 'Brad', + AppraisedValue: 400, +}; + +const mockAllAssetsBuffer = Buffer.from( + JSON.stringify([mockAsset1, mockAsset2]) +); // TODO add tests for server errors -// TODO implement 405 Method Not Allowed where appropriate and add tests describe('Asset Transfer Besic REST API', () => { let app: Application; + let mockJobQueue: MockProxy; beforeEach(async () => { app = await createServer(); + + const mockJob = mock(); + mockJob.id = '1'; + mockJobQueue = mock(); + mockJobQueue.add.mockResolvedValue(mockJob); + app.set('jobq', mockJobQueue); }); describe('/ready', () => { @@ -35,6 +68,31 @@ describe('Asset Transfer Besic REST API', () => { describe('/live', () => { it('GET should respond with 200 OK json', async () => { + const mockBlockchainInfoProto = + fabricProtos.common.BlockchainInfo.create(); + mockBlockchainInfoProto.height = 42; + const mockBlockchainInfoBuffer = Buffer.from( + fabricProtos.common.BlockchainInfo.encode( + mockBlockchainInfoProto + ).finish() + ); + + const mockOrg1QsccContract = mock(); + mockOrg1QsccContract.evaluateTransaction + .calledWith('GetChainInfo') + .mockResolvedValue(mockBlockchainInfoBuffer); + app.set(config.mspIdOrg1, { + qsccContract: mockOrg1QsccContract, + }); + + const mockOrg2QsccContract = mock(); + mockOrg2QsccContract.evaluateTransaction + .calledWith('GetChainInfo') + .mockResolvedValue(mockBlockchainInfoBuffer); + app.set(config.mspIdOrg2, { + qsccContract: mockOrg2QsccContract, + }); + const response = await request(app).get('/live'); expect(response.statusCode).toEqual(200); expect(response.header).toHaveProperty( @@ -49,6 +107,19 @@ describe('Asset Transfer Besic REST API', () => { }); describe('/api/assets', () => { + let mockGetAllAssetsTransaction: MockProxy; + + beforeEach(() => { + mockGetAllAssetsTransaction = mock(); + const mockBasicContract = mock(); + mockBasicContract.createTransaction + .calledWith('GetAllAssets') + .mockReturnValue(mockGetAllAssetsTransaction); + app.set(config.mspIdOrg1, { + assetContract: mockBasicContract, + }); + }); + it('GET should respond with 401 unauthorized json when an invalid API key is specified', async () => { const response = await request(app) .get('/api/assets') @@ -66,8 +137,8 @@ describe('Asset Transfer Besic REST API', () => { }); it('GET should respond with an empty json array when there are no assets', async () => { - // NOTE: only the first mocked GetAllAssets with return no assets - // TODO find a better alternative so that test order does not matter + mockGetAllAssetsTransaction.evaluate.mockResolvedValue(Buffer.from('')); + const response = await request(app) .get('/api/assets') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); @@ -80,8 +151,10 @@ describe('Asset Transfer Besic REST API', () => { }); it('GET should respond with json array of assets', async () => { - // NOTE: only the second mocked GetAllAssets with return no assets - // TODO find a better alternative so that test order does not matter + mockGetAllAssetsTransaction.evaluate.mockResolvedValue( + mockAllAssetsBuffer + ); + const response = await request(app) .get('/api/assets') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); @@ -180,37 +253,34 @@ describe('Asset Transfer Besic REST API', () => { ); expect(response.body).toEqual({ status: 'Accepted', - transactionId: 'txn1', - timestamp: expect.any(String), - }); - }); - - it('POST should respond with 409 conflict json when asset already exists', async () => { - const response = await request(app) - .post('/api/assets') - .send({ - id: 'asset1', - color: 'blue', - size: 5, - owner: 'Tomoko', - appraisedValue: 300, - }) - .set('X-Api-Key', 'ORG1MOCKAPIKEY'); - expect(response.statusCode).toEqual(409); - expect(response.header).toHaveProperty( - 'content-type', - 'application/json; charset=utf-8' - ); - expect(response.body).toEqual({ - status: 'Conflict', - reason: 'ASSET_EXISTS', - message: 'the asset asset1 already exists', + jobId: '1', timestamp: expect.any(String), }); }); }); describe('/api/assets/:id', () => { + let mockAssetExistsTransaction: MockProxy; + let mockReadAssetTransaction: MockProxy; + + beforeEach(() => { + const mockBasicContract = mock(); + + mockAssetExistsTransaction = mock(); + mockBasicContract.createTransaction + .calledWith('AssetExists') + .mockReturnValue(mockAssetExistsTransaction); + + mockReadAssetTransaction = mock(); + mockBasicContract.createTransaction + .calledWith('ReadAsset') + .mockReturnValue(mockReadAssetTransaction); + + app.set(config.mspIdOrg1, { + assetContract: mockBasicContract, + }); + }); + it('OPTIONS should respond with 401 unauthorized json when an invalid API key is specified', async () => { const response = await request(app) .options('/api/assets/asset1') @@ -228,6 +298,10 @@ describe('Asset Transfer Besic REST API', () => { }); it('OPTIONS should respond with 404 not found json without the allow header when there is no asset with the specified ID', async () => { + mockAssetExistsTransaction.evaluate + .calledWith('asset3') + .mockResolvedValue(Buffer.from('false')); + const response = await request(app) .options('/api/assets/asset3') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); @@ -244,6 +318,10 @@ describe('Asset Transfer Besic REST API', () => { }); it('OPTIONS should respond with 200 OK json with the allow header', async () => { + mockAssetExistsTransaction.evaluate + .calledWith('asset1') + .mockResolvedValue(Buffer.from('true')); + const response = await request(app) .options('/api/assets/asset1') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); @@ -279,6 +357,10 @@ describe('Asset Transfer Besic REST API', () => { }); it('GET should respond with 404 not found json when there is no asset with the specified ID', async () => { + mockReadAssetTransaction.evaluate + .calledWith('asset3') + .mockRejectedValue(new Error('the asset asset3 does not exist')); + const response = await request(app) .get('/api/assets/asset3') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); @@ -294,6 +376,10 @@ describe('Asset Transfer Besic REST API', () => { }); it('GET should respond with the asset json when the asset exists', async () => { + mockReadAssetTransaction.evaluate + .calledWith('asset1') + .mockResolvedValue(mockAsset1Buffer); + const response = await request(app) .get('/api/assets/asset1') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); @@ -334,28 +420,6 @@ describe('Asset Transfer Besic REST API', () => { }); }); - it('PUT should respond with 404 not found json when there is no asset with the specified ID', async () => { - const response = await request(app) - .put('/api/assets/asset3') - .send({ - id: 'asset3', - color: 'red', - size: 5, - owner: 'Brad', - appraisedValue: 400, - }) - .set('X-Api-Key', 'ORG1MOCKAPIKEY'); - expect(response.statusCode).toEqual(404); - expect(response.header).toHaveProperty( - 'content-type', - 'application/json; charset=utf-8' - ); - expect(response.body).toEqual({ - status: 'Not Found', - timestamp: expect.any(String), - }); - }); - it('PUT should respond with 400 bad request json when IDs do not match', async () => { const response = await request(app) .put('/api/assets/asset1') @@ -429,7 +493,7 @@ describe('Asset Transfer Besic REST API', () => { ); expect(response.body).toEqual({ status: 'Accepted', - transactionId: 'txn1', + jobId: '1', timestamp: expect.any(String), }); }); @@ -451,22 +515,6 @@ describe('Asset Transfer Besic REST API', () => { }); }); - it('PATCH should respond with 404 not found json when there is no asset with the specified ID', async () => { - const response = await request(app) - .patch('/api/assets/asset3') - .send([{ op: 'replace', path: '/owner', value: 'Ashleigh' }]) - .set('X-Api-Key', 'ORG1MOCKAPIKEY'); - expect(response.statusCode).toEqual(404); - expect(response.header).toHaveProperty( - 'content-type', - 'application/json; charset=utf-8' - ); - expect(response.body).toEqual({ - status: 'Not Found', - timestamp: expect.any(String), - }); - }); - it('PATCH should respond with 400 bad request json for invalid patch op/path', async () => { const response = await request(app) .patch('/api/assets/asset1') @@ -505,7 +553,7 @@ describe('Asset Transfer Besic REST API', () => { ); expect(response.body).toEqual({ status: 'Accepted', - transactionId: 'txn1', + jobId: '1', timestamp: expect.any(String), }); }); @@ -526,9 +574,45 @@ describe('Asset Transfer Besic REST API', () => { }); }); - it('DELETE should respond with 404 not found json when there is no asset with the specified ID', async () => { + it('DELETE should respond with 202 accepted json', async () => { const response = await request(app) - .delete('/api/assets/asset3') + .delete('/api/assets/asset1') + .set('X-Api-Key', 'ORG1MOCKAPIKEY'); + expect(response.statusCode).toEqual(202); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + status: 'Accepted', + jobId: '1', + timestamp: expect.any(String), + }); + }); + }); + + describe('/api/jobs/:id', () => { + it('GET should respond with 401 unauthorized json when an invalid API key is specified', async () => { + const response = await request(app) + .get('/api/jobs/1') + .set('X-Api-Key', 'NOTTHERIGHTAPIKEY'); + expect(response.statusCode).toEqual(401); + expect(response.header).toHaveProperty( + 'content-type', + 'application/json; charset=utf-8' + ); + expect(response.body).toEqual({ + reason: 'NO_VALID_APIKEY', + status: 'Unauthorized', + timestamp: expect.any(String), + }); + }); + + it('GET should respond with 404 not found json when there is no job with the specified ID', async () => { + mocked(Job.fromId).mockResolvedValue(undefined); + + const response = await request(app) + .get('/api/jobs/3') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); expect(response.statusCode).toEqual(404); expect(response.header).toHaveProperty( @@ -541,24 +625,49 @@ describe('Asset Transfer Besic REST API', () => { }); }); - it('DELETE should respond with 202 accepted json', async () => { + it('GET should respond with json details for the specified job ID', async () => { + const mockJob = mock(); + mockJob.id = '2'; + mockJob.data = { + transactionIds: ['txn1', 'txn2'], + }; + mockJob.returnvalue = { + transactionError: 'Mock error', + transactionPayload: Buffer.from('Mock payload'), + }; + mockJobQueue.getJob.calledWith('2').mockResolvedValue(mockJob); + const response = await request(app) - .delete('/api/assets/asset1') + .get('/api/jobs/2') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); - expect(response.statusCode).toEqual(202); + expect(response.statusCode).toEqual(200); expect(response.header).toHaveProperty( 'content-type', 'application/json; charset=utf-8' ); expect(response.body).toEqual({ - status: 'Accepted', - transactionId: 'txn1', - timestamp: expect.any(String), + jobId: '2', + transactionIds: ['txn1', 'txn2'], + transactionError: 'Mock error', + transactionPayload: 'Mock payload', }); }); }); describe('/api/transactions/:id', () => { + let mockGetTransactionByIDTransaction: MockProxy; + + beforeEach(() => { + mockGetTransactionByIDTransaction = mock(); + const mockQsccContract = mock(); + mockQsccContract.createTransaction + .calledWith('GetTransactionByID') + .mockReturnValue(mockGetTransactionByIDTransaction); + app.set(config.mspIdOrg1, { + qsccContract: mockQsccContract, + }); + }); + it('GET should respond with 401 unauthorized json when an invalid API key is specified', async () => { const response = await request(app) .get('/api/transactions/txn1') @@ -576,6 +685,14 @@ describe('Asset Transfer Besic REST API', () => { }); it('GET should respond with 404 not found json when there is no transaction with the specified ID', async () => { + mockGetTransactionByIDTransaction.evaluate + .calledWith('mychannel', 'txn3') + .mockRejectedValue( + new Error( + 'Failed to get transaction with id txn3, error Entry not found in index' + ) + ); + const response = await request(app) .get('/api/transactions/txn3') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); @@ -591,6 +708,19 @@ describe('Asset Transfer Besic REST API', () => { }); it('GET should respond with json details for the specified transaction ID', async () => { + const processedTransactionProto = + fabricProtos.protos.ProcessedTransaction.create(); + processedTransactionProto.validationCode = + fabricProtos.protos.TxValidationCode.VALID; + const processedTransactionBuffer = Buffer.from( + fabricProtos.protos.ProcessedTransaction.encode( + processedTransactionProto + ).finish() + ); + mockGetTransactionByIDTransaction.evaluate + .calledWith('mychannel', 'txn2') + .mockResolvedValue(processedTransactionBuffer); + const response = await request(app) .get('/api/transactions/txn2') .set('X-Api-Key', 'ORG1MOCKAPIKEY'); @@ -600,10 +730,8 @@ describe('Asset Transfer Besic REST API', () => { 'application/json; charset=utf-8' ); expect(response.body).toEqual({ - status: 'OK', - progress: 'DONE', + transactionId: 'txn2', validationCode: 'VALID', - timestamp: expect.any(String), }); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 6bac3866..5d6c96f5 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -1,32 +1,35 @@ /* * SPDX-License-Identifier: Apache-2.0 * - * Note: this sample is intended to work with the basic asset transfer + * This sample is intended to work with the basic asset transfer * chaincode which imposes some constraints on what is possible here. * * For example, * - There is no validation for Asset IDs * - There are no error codes from the chaincode * + * To avoid timeouts, long running tasks should be decoupled from HTTP request + * processing + * + * Submit transactions can potentially be very long running, especially if the + * transaction fails and needs to be retried one or more times + * + * To allow requests to respond quickly enough, this sample queues submit + * requests for processing asynchronously and immediately returns 202 Accepted */ import express, { Request, Response } from 'express'; import { body, validationResult } from 'express-validator'; import { Contract } from 'fabric-network'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; -import { Redis } from 'ioredis'; -import { AssetExistsError, AssetNotFoundError } from './errors'; -import { evatuateTransaction, submitTransaction } from './fabric'; +import { Queue } from 'bullmq'; +import { AssetNotFoundError } from './errors'; +import { evatuateTransaction } from './fabric'; +import { addSubmitTransactionJob } from './jobs'; import { logger } from './logger'; -const { - ACCEPTED, - BAD_REQUEST, - CONFLICT, - INTERNAL_SERVER_ERROR, - NOT_FOUND, - OK, -} = StatusCodes; +const { ACCEPTED, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = + StatusCodes; export const assetsRouter = express.Router(); @@ -45,7 +48,7 @@ assetsRouter.get('/', async (req: Request, res: Response) => { return res.status(OK).json(assets); } catch (err) { - logger.error(err, 'Error processing get all assets request'); + logger.error({ err }, 'Error processing get all assets request'); return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -76,14 +79,12 @@ assetsRouter.post( } const mspId = req.user as string; - const contract = req.app.get(mspId).assetContract as Contract; - const redis = req.app.get('redis') as Redis; const assetId = req.body.id; try { - const transactionId = await submitTransaction( - contract, - redis, + const submitQueue = req.app.get('jobq') as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, mspId, 'CreateAsset', assetId, @@ -95,26 +96,16 @@ assetsRouter.post( return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), - transactionId: transactionId, + jobId: jobId, timestamp: new Date().toISOString(), }); } catch (err) { logger.error( - err, - 'Error processing create asset request for asset ID %s with transaction ID %s', - assetId, - err.transactionId + { err }, + 'Error processing create asset request for asset ID %s', + assetId ); - if (err instanceof AssetExistsError) { - return res.status(CONFLICT).json({ - status: getReasonPhrase(CONFLICT), - reason: 'ASSET_EXISTS', - message: err.message, - timestamp: new Date().toISOString(), - }); - } - return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -152,7 +143,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { } } catch (err) { logger.error( - err, + { err }, 'Error processing asset options request for asset ID %s', assetId ); @@ -177,7 +168,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { return res.status(OK).json(asset); } catch (err) { logger.error( - err, + { err }, 'Error processing read asset request for asset ID %s', assetId ); @@ -228,14 +219,12 @@ assetsRouter.put( } const mspId = req.user as string; - const contract = req.app.get(mspId).assetContract as Contract; - const redis = req.app.get('redis') as Redis; const assetId = req.params.assetId; try { - const transactionId = await submitTransaction( - contract, - redis, + const submitQueue = req.app.get('jobq') as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, mspId, 'UpdateAsset', assetId, @@ -247,24 +236,16 @@ assetsRouter.put( return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), - transactionId: transactionId, + jobId: jobId, timestamp: new Date().toISOString(), }); } catch (err) { logger.error( - err, - 'Error processing update asset request for asset ID %s with transaction ID %s', - assetId, - err.transactionId + { err }, + 'Error processing update asset request for asset ID %s', + assetId ); - if (err instanceof AssetNotFoundError) { - return res.status(NOT_FOUND).json({ - status: getReasonPhrase(NOT_FOUND), - timestamp: new Date().toISOString(), - }); - } - return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -299,15 +280,13 @@ assetsRouter.patch( } const mspId = req.user as string; - const contract = req.app.get(mspId).assetContract as Contract; - const redis = req.app.get('redis') as Redis; const assetId = req.params.assetId; const newOwner = req.body[0].value; try { - const transactionId = await submitTransaction( - contract, - redis, + const submitQueue = req.app.get('jobq') as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, mspId, 'TransferAsset', assetId, @@ -316,24 +295,16 @@ assetsRouter.patch( return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), - transactionId: transactionId, + jobId: jobId, timestamp: new Date().toISOString(), }); } catch (err) { logger.error( - err, - 'Error processing update asset request for asset ID %s with transaction ID %s', - req.params.assetId, - err.transactionId + { err }, + 'Error processing update asset request for asset ID %s', + req.params.assetId ); - if (err instanceof AssetNotFoundError) { - return res.status(NOT_FOUND).json({ - status: getReasonPhrase(NOT_FOUND), - timestamp: new Date().toISOString(), - }); - } - return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), @@ -346,14 +317,12 @@ assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { logger.debug(req.body, 'Delete asset request received'); const mspId = req.user as string; - const contract = req.app.get(mspId).assetContract as Contract; - const redis = req.app.get('redis') as Redis; const assetId = req.params.assetId; try { - const transactionId = await submitTransaction( - contract, - redis, + const submitQueue = req.app.get('jobq') as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, mspId, 'DeleteAsset', assetId @@ -361,24 +330,16 @@ assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { return res.status(ACCEPTED).json({ status: getReasonPhrase(ACCEPTED), - transactionId: transactionId, + jobId: jobId, timestamp: new Date().toISOString(), }); } catch (err) { logger.error( - err, - 'Error processing delete asset request for asset ID %s with transaction ID %s', - assetId, - err.transactionId + { err }, + 'Error processing delete asset request for asset ID %s', + assetId ); - if (err instanceof AssetNotFoundError) { - return res.status(NOT_FOUND).json({ - status: getReasonPhrase(NOT_FOUND), - timestamp: new Date().toISOString(), - }); - } - return res.status(INTERNAL_SERVER_ERROR).json({ status: getReasonPhrase(INTERNAL_SERVER_ERROR), timestamp: new Date().toISOString(), diff --git a/asset-transfer-basic/rest-api-typescript/src/config.spec.ts b/asset-transfer-basic/rest-api-typescript/src/config.spec.ts index fdd5d91e..f095c1b5 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.spec.ts @@ -60,46 +60,156 @@ describe('Config values', () => { }); }); - describe('retryDelay', () => { - it('defaults to "3000"', () => { + describe('submitJobBackoffType', () => { + it('defaults to "fixed"', () => { const config = require('./config'); - expect(config.retryDelay).toBe(3000); + expect(config.submitJobBackoffType).toBe('fixed'); }); - it('can be configured using the "RETRY_DELAY" environment variable', () => { - process.env.RETRY_DELAY = '9999'; + it('can be configured using the "SUBMIT_JOB_BACKOFF_TYPE" environment variable', () => { + process.env.SUBMIT_JOB_BACKOFF_TYPE = 'exponential'; const config = require('./config'); - expect(config.retryDelay).toBe(9999); + expect(config.submitJobBackoffType).toBe('exponential'); }); - it('throws an error when the "RETRY_DELAY" environment variable has an invalid number', () => { - process.env.RETRY_DELAY = 'short'; + it('throws an error when the "LOG_LEVEL" environment variable has an invalid log level', () => { + process.env.SUBMIT_JOB_BACKOFF_TYPE = 'jitter'; expect(() => { require('./config'); }).toThrow( - 'env-var: "RETRY_DELAY" should be a valid integer. An example of a valid value would be: 3000' + 'env-var: "SUBMIT_JOB_BACKOFF_TYPE" should be one of [fixed, exponential]' ); }); }); - describe('maxRetryCount', () => { - it('defaults to "5"', () => { + describe('submitJobBackoffDelay', () => { + it('defaults to "3000"', () => { const config = require('./config'); - expect(config.maxRetryCount).toBe(5); + expect(config.submitJobBackoffDelay).toBe(3000); }); - it('can be configured using the "MAX_RETRY_COUNT" environment variable', () => { - process.env.MAX_RETRY_COUNT = '9999'; + it('can be configured using the "SUBMIT_JOB_BACKOFF_DELAY" environment variable', () => { + process.env.SUBMIT_JOB_BACKOFF_DELAY = '9999'; const config = require('./config'); - expect(config.maxRetryCount).toBe(9999); + expect(config.submitJobBackoffDelay).toBe(9999); }); - it('throws an error when the "MAX_RETRY_COUNT" environment variable has an invalid number', () => { - process.env.MAX_RETRY_COUNT = 'lots'; + it('throws an error when the "SUBMIT_JOB_BACKOFF_DELAY" environment variable has an invalid number', () => { + process.env.SUBMIT_JOB_BACKOFF_DELAY = 'short'; expect(() => { require('./config'); }).toThrow( - 'env-var: "MAX_RETRY_COUNT" should be a valid integer. An example of a valid value would be: 5' + 'env-var: "SUBMIT_JOB_BACKOFF_DELAY" should be a valid integer. An example of a valid value would be: 3000' + ); + }); + }); + + describe('submitJobAttempts', () => { + it('defaults to "5"', () => { + const config = require('./config'); + expect(config.submitJobAttempts).toBe(5); + }); + + it('can be configured using the "SUBMIT_JOB_ATTEMPTS" environment variable', () => { + process.env.SUBMIT_JOB_ATTEMPTS = '9999'; + const config = require('./config'); + expect(config.submitJobAttempts).toBe(9999); + }); + + it('throws an error when the "SUBMIT_JOB_ATTEMPTS" environment variable has an invalid number', () => { + process.env.SUBMIT_JOB_ATTEMPTS = 'lots'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "SUBMIT_JOB_ATTEMPTS" should be a valid integer. An example of a valid value would be: 5' + ); + }); + }); + + describe('submitJobConcurrency', () => { + it('defaults to "5"', () => { + const config = require('./config'); + expect(config.submitJobConcurrency).toBe(5); + }); + + it('can be configured using the "SUBMIT_JOB_CONCURRENCY" environment variable', () => { + process.env.SUBMIT_JOB_CONCURRENCY = '9999'; + const config = require('./config'); + expect(config.submitJobConcurrency).toBe(9999); + }); + + it('throws an error when the "SUBMIT_JOB_CONCURRENCY" environment variable has an invalid number', () => { + process.env.SUBMIT_JOB_CONCURRENCY = 'lots'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "SUBMIT_JOB_CONCURRENCY" should be a valid integer. An example of a valid value would be: 5' + ); + }); + }); + + describe('maxCompletedSubmitJobs', () => { + it('defaults to "1000"', () => { + const config = require('./config'); + expect(config.maxCompletedSubmitJobs).toBe(1000); + }); + + it('can be configured using the "MAX_COMPLETED_SUBMIT_JOBS" environment variable', () => { + process.env.MAX_COMPLETED_SUBMIT_JOBS = '9999'; + const config = require('./config'); + expect(config.maxCompletedSubmitJobs).toBe(9999); + }); + + it('throws an error when the "MAX_COMPLETED_SUBMIT_JOBS" environment variable has an invalid number', () => { + process.env.MAX_COMPLETED_SUBMIT_JOBS = 'lots'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "MAX_COMPLETED_SUBMIT_JOBS" should be a valid integer. An example of a valid value would be: 1000' + ); + }); + }); + + describe('maxFailedSubmitJobs', () => { + it('defaults to "1000"', () => { + const config = require('./config'); + expect(config.maxFailedSubmitJobs).toBe(1000); + }); + + it('can be configured using the "MAX_FAILED_SUBMIT_JOBS" environment variable', () => { + process.env.MAX_FAILED_SUBMIT_JOBS = '9999'; + const config = require('./config'); + expect(config.maxFailedSubmitJobs).toBe(9999); + }); + + it('throws an error when the "MAX_FAILED_SUBMIT_JOBS" environment variable has an invalid number', () => { + process.env.MAX_FAILED_SUBMIT_JOBS = 'lots'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "MAX_FAILED_SUBMIT_JOBS" should be a valid integer. An example of a valid value would be: 1000' + ); + }); + }); + + describe('submitJobQueueScheduler', () => { + it('defaults to "true"', () => { + const config = require('./config'); + expect(config.submitJobQueueScheduler).toBe(true); + }); + + it('can be configured using the "SUBMIT_JOB_QUEUE_SCHEDULER" environment variable', () => { + process.env.SUBMIT_JOB_QUEUE_SCHEDULER = 'false'; + const config = require('./config'); + expect(config.submitJobQueueScheduler).toBe(false); + }); + + it('throws an error when the "SUBMIT_JOB_QUEUE_SCHEDULER" environment variable has an invalid boolean value', () => { + process.env.SUBMIT_JOB_QUEUE_SCHEDULER = '11'; + expect(() => { + require('./config'); + }).toThrow( + 'env-var: "SUBMIT_JOB_QUEUE_SCHEDULER" should be either "true", "false", "TRUE", or "FALSE". An example of a valid value would be: true' ); }); }); @@ -152,28 +262,6 @@ describe('Config values', () => { }); }); - describe('blockListenerOrg', () => { - it('defaults to "Org1"', () => { - const config = require('./config'); - expect(config.blockListenerOrg).toBe('Org1'); - }); - - it('can be configured using the "HLF_BLOCK_LISTENER_ORG" environment variable', () => { - process.env.HLF_BLOCK_LISTENER_ORG = 'Org2'; - const config = require('./config'); - expect(config.blockListenerOrg).toBe('Org2'); - }); - - it('throws an error when the "HLF_BLOCK_LISTENER_ORG" environment variable has an invalid value', () => { - process.env.HLF_BLOCK_LISTENER_ORG = 'Org3'; - expect(() => { - require('./config'); - }).toThrow( - 'env-var: "HLF_BLOCK_LISTENER_ORG" should be one of [Org1, Org2]' - ); - }); - }); - describe('channelName', () => { it('defaults to "mychannel"', () => { const config = require('./config'); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 47c0f909..a15c0cec 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -7,6 +7,8 @@ import * as env from 'env-var'; export const ORG1 = 'Org1'; export const ORG2 = 'Org2'; +export const JOB_QUEUE_NAME = 'submit'; + /* * Log level for the REST server */ @@ -25,23 +27,69 @@ export const port = env .asPortNumber(); /* - * The delay between each retry attempt in milliseconds + * The type of backoff to use for retrying failed submit jobs */ -export const retryDelay = env - .get('RETRY_DELAY') +export const submitJobBackoffType = env + .get('SUBMIT_JOB_BACKOFF_TYPE') + .default('fixed') + .asEnum(['fixed', 'exponential']); + +/* + * Backoff delay for retrying failed submit jobs in milliseconds + */ +export const submitJobBackoffDelay = env + .get('SUBMIT_JOB_BACKOFF_DELAY') .default('3000') .example('3000') .asIntPositive(); /* - * The maximum number of times to retry a failing transaction + * The total number of attempts to try a submit job until it completes */ -export const maxRetryCount = env - .get('MAX_RETRY_COUNT') +export const submitJobAttempts = env + .get('SUBMIT_JOB_ATTEMPTS') .default('5') .example('5') .asIntPositive(); +/* + * The maximum number of submit jobs that can be processed in parallel + */ +export const submitJobConcurrency = env + .get('SUBMIT_JOB_CONCURRENCY') + .default('5') + .example('5') + .asIntPositive(); + +/* + * The number of completed submit jobs to keep + */ +export const maxCompletedSubmitJobs = env + .get('MAX_COMPLETED_SUBMIT_JOBS') + .default('1000') + .example('1000') + .asIntPositive(); + +/* + * The number of failed submit jobs to keep + */ +export const maxFailedSubmitJobs = env + .get('MAX_FAILED_SUBMIT_JOBS') + .default('1000') + .example('1000') + .asIntPositive(); + +/* + * Whether to initialise a scheduler for the submit job queue + * There must be at least on queue scheduler to handle retries and you may want + * more than one for redundancy + */ +export const submitJobQueueScheduler = env + .get('SUBMIT_JOB_QUEUE_SCHEDULER') + .default('true') + .example('true') + .asBoolStrict(); + /* * Whether to convert discovered host addresses to be 'localhost' * This should be set to 'true' when running a docker composed fabric network on the @@ -71,14 +119,6 @@ export const mspIdOrg2 = env .example(`${ORG2}MSP`) .asString(); -/* - * The block listener org - */ -export const blockListenerOrg = env - .get('HLF_BLOCK_LISTENER_ORG') - .default(ORG1) - .asEnum([ORG1, ORG2]); - /* * Name of the channel which the basic asset sample chaincode has been installed on */ @@ -205,7 +245,7 @@ export const redisPort = env */ export const redisUsername = env .get('REDIS_USERNAME') - .example('conga') + .example('fabric') .asString(); /* diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts b/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts index a0813c90..6ef490f6 100644 --- a/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts @@ -5,15 +5,55 @@ import { AssetExistsError, AssetNotFoundError, - TransactionError, TransactionNotFoundError, handleError, isDuplicateTransactionError, + isErrorLike, } from './errors'; describe('Errors', () => { + describe('isErrorLike', () => { + it('returns false for null', () => { + expect(isErrorLike(null)).toBe(false); + }); + + it('returns false for undefined', () => { + expect(isErrorLike(undefined)).toBe(false); + }); + + it('returns false for empty object', () => { + expect(isErrorLike({})).toBe(false); + }); + + it('returns false for string', () => { + expect(isErrorLike('true')).toBe(false); + }); + + it('returns false for non-error object', () => { + expect(isErrorLike({ size: 42 })).toBe(false); + }); + + it('returns false for invalid error object', () => { + expect(isErrorLike({ name: 'MockError', message: 42 })).toBe(false); + }); + + it('returns false for error like object with invalid stack', () => { + expect( + isErrorLike({ name: 'MockError', message: 'Fail', stack: false }) + ).toBe(false); + }); + + it('returns true for error like object', () => { + expect(isErrorLike({ name: 'MockError', message: 'Fail' })).toBe(true); + }); + + it('returns true for new Error', () => { + expect(isErrorLike(new Error('Error'))).toBe(true); + }); + }); + describe('isDuplicateTransactionError', () => { - it('returns true for an error with duplicate transaction endorsement details', () => { + it('returns true for an error when all endorsement details are duplicate transaction found', () => { const mockDuplicateTransactionError = { errors: [ { @@ -21,6 +61,36 @@ describe('Errors', () => { { details: 'duplicate transaction found', }, + { + details: 'duplicate transaction found', + }, + { + details: 'duplicate transaction found', + }, + ], + }, + ], + }; + + expect(isDuplicateTransactionError(mockDuplicateTransactionError)).toBe( + true + ); + }); + + it('returns true for an error when at least one endorsement details are duplicate transaction found', () => { + const mockDuplicateTransactionError = { + errors: [ + { + endorsements: [ + { + details: 'duplicate transaction found', + }, + { + details: 'mock endorsement details', + }, + { + details: 'mock endorsement details', + }, ], }, ], @@ -39,6 +109,9 @@ describe('Errors', () => { { details: 'mock endorsement details', }, + { + details: 'mock endorsement details', + }, ], }, ], @@ -48,6 +121,38 @@ describe('Errors', () => { false ); }); + + it('returns false for an error without endorsement details', () => { + const mockDuplicateTransactionError = { + errors: [ + { + rejections: [ + { + details: 'duplicate transaction found', + }, + ], + }, + ], + }; + + expect(isDuplicateTransactionError(mockDuplicateTransactionError)).toBe( + false + ); + }); + + it('returns false for a basic Error object without endorsement details', () => { + expect( + isDuplicateTransactionError(new Error('duplicate transaction found')) + ).toBe(false); + }); + + it('returns false for an undefined error', () => { + expect(isDuplicateTransactionError(undefined)).toBe(false); + }); + + it('returns false for a null error', () => { + expect(isDuplicateTransactionError(null)).toBe(false); + }); }); describe('handleError', () => { @@ -77,25 +182,27 @@ describe('Errors', () => { } ); - it('returns a TransactionNotFoundError for errors with a transaction not found message', () => { - expect( - handleError( - 'txn1', - new Error( - 'Failed to get transaction with id txn, error Entry not found in index' - ) - ) - ).toStrictEqual( - new TransactionNotFoundError( - 'Failed to get transaction with id txn, error Entry not found in index', - 'txn1' - ) + it.each([ + 'Failed to get transaction with id txn, error Entry not found in index', + 'Failed to get transaction with id txn, error no such transaction ID [txn] in index', + ])( + 'returns a TransactionNotFoundError for errors with a transaction not found message: %s', + (msg) => { + expect(handleError('txn1', new Error(msg))).toStrictEqual( + new TransactionNotFoundError(msg, 'txn1') + ); + } + ); + + it('returns the original error for errors with other messages', () => { + expect(handleError('txn1', new Error('MOCK ERROR'))).toStrictEqual( + new Error('MOCK ERROR') ); }); - it('returns a TransactionError for errors with other messages', () => { - expect(handleError('txn1', new Error('MOCK ERROR'))).toStrictEqual( - new TransactionError('Transaction error', 'txn1') + it('returns a new Error object for errors of other types', () => { + expect(handleError('txn1', 42)).toStrictEqual( + new Error('Unhandled error: 42') ); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.ts b/asset-transfer-basic/rest-api-typescript/src/errors.ts index 5a1fde2e..89eaaa6b 100644 --- a/asset-transfer-basic/rest-api-typescript/src/errors.ts +++ b/asset-transfer-basic/rest-api-typescript/src/errors.ts @@ -4,23 +4,23 @@ import { logger } from './logger'; -export class TransactionError extends Error { +export class ContractError extends Error { transactionId: string; constructor(message: string, transactionId: string) { super(message); - Object.setPrototypeOf(this, TransactionError.prototype); + Object.setPrototypeOf(this, ContractError.prototype); this.name = 'TransactionError'; this.transactionId = transactionId; } } -export class TransactionNotFoundError extends Error { +export class TransactionNotFoundError extends ContractError { transactionId: string; constructor(message: string, transactionId: string) { - super(message); + super(message, transactionId); Object.setPrototypeOf(this, TransactionNotFoundError.prototype); this.name = 'TransactionNotFoundError'; @@ -28,7 +28,7 @@ export class TransactionNotFoundError extends Error { } } -export class AssetExistsError extends TransactionError { +export class AssetExistsError extends ContractError { constructor(message: string, transactionId: string) { super(message, transactionId); Object.setPrototypeOf(this, AssetExistsError.prototype); @@ -37,7 +37,7 @@ export class AssetExistsError extends TransactionError { } } -export class AssetNotFoundError extends TransactionError { +export class AssetNotFoundError extends ContractError { constructor(message: string, transactionId: string) { super(message, transactionId); Object.setPrototypeOf(this, AssetNotFoundError.prototype); @@ -46,6 +46,29 @@ export class AssetNotFoundError extends TransactionError { } } +export class JobNotFoundError extends Error { + jobId: string; + + constructor(message: string, jobId: string) { + super(message); + Object.setPrototypeOf(this, JobNotFoundError.prototype); + + this.name = 'JobNotFoundError'; + this.jobId = jobId; + } +} + +export const isErrorLike = (err: unknown): err is Error => { + return ( + err != undefined && + err != null && + typeof (err as Error).name === 'string' && + typeof (err as Error).message === 'string' && + ((err as Error).stack === undefined || + typeof (err as Error).stack === 'string') + ); +}; + /* * Checks whether an error was caused by a duplicate transaction. * @@ -54,19 +77,103 @@ export class AssetNotFoundError extends TransactionError { * DUPLICATE_TXID TxValidationCode somehow but that does not seem to be * possible. */ -export const isDuplicateTransactionError = (error: { - errors: { endorsements: { details: string }[] }[]; -}): boolean => { - try { - const isDuplicateTxn = error?.errors?.some((err) => - err?.endorsements?.some((endorsement) => - endorsement?.details?.startsWith('duplicate transaction found') - ) - ); +export const isDuplicateTransactionError = (err: unknown): boolean => { + if (err === undefined || err === null) return false; - return isDuplicateTxn; - } catch (err) { - logger.warn(err, 'Error checking for duplicate transaction'); + const endorsementError = err as { + errors: { endorsements: { details: string }[] }[]; + }; + + const isDuplicate = endorsementError?.errors?.some((err) => + err?.endorsements?.some((endorsement) => + endorsement?.details?.startsWith('duplicate transaction found') + ) + ); + + return isDuplicate === true; +}; + +/* + * Matches asset already exists error strings from the asset contract + * + * The regex needs to match the following error messages: + * "the asset %s already exists" + * "The asset ${id} already exists" + * "Asset %s already exists" + */ +const matchAssetAlreadyExistsMessage = (message: string): string | null => { + // + const assetAlreadyExistsRegex = /([tT]he )?[aA]sset \w* already exists/g; + const assetAlreadyExistsMatch = message.match(assetAlreadyExistsRegex); + logger.debug( + { message: message, result: assetAlreadyExistsMatch }, + 'Checking for asset already exists message' + ); + + if (assetAlreadyExistsMatch !== null) { + return assetAlreadyExistsMatch[0]; + } + + return null; +}; + +/* + * Matches asset does not exist error strings from the asset contract + * + * The regex needs to match the following error messages: + * "the asset %s does not exist" + * "The asset ${id} does not exist" + * "Asset %s does not exist" + */ +const matchAssetDoesNotExistMessage = (message: string): string | null => { + const assetDoesNotExistRegex = /([tT]he )?[aA]sset \w* does not exist/g; + const assetDoesNotExistMatch = message.match(assetDoesNotExistRegex); + logger.debug( + { message: message, result: assetDoesNotExistMatch }, + 'Checking for asset does not exist message' + ); + + if (assetDoesNotExistMatch !== null) { + return assetDoesNotExistMatch[0]; + } + + return null; +}; + +/* + * Matches transaction does not exist error strings from the contract API + * + * The regex needs to match the following error messages: + * "Failed to get transaction with id %s, error Entry not found in index" + * "Failed to get transaction with id %s, error no such transaction ID [%s] in index" + */ +const matchTransactionDoesNotExistMessage = ( + message: string +): string | null => { + const transactionDoesNotExistRegex = + /Failed to get transaction with id [^,]*, error (?:(?:Entry not found)|(?:no such transaction ID \[[^\]]*\])) in index/g; + const transactionDoesNotExistMatch = message.match( + transactionDoesNotExistRegex + ); + logger.debug( + { message: message, result: transactionDoesNotExistMatch }, + 'Checking for transaction does not exist message' + ); + + if (transactionDoesNotExistMatch !== null) { + return transactionDoesNotExistMatch[0]; + } + + return null; +}; + +export const isContractError = (err: unknown): boolean => { + if ( + err instanceof AssetExistsError || + err instanceof AssetNotFoundError || + err instanceof TransactionNotFoundError + ) { + return true; } return false; @@ -80,56 +187,32 @@ export const isDuplicateTransactionError = (error: { * again it's the only option. The error message text is not even the same for * the Go, Java, and Javascript implementations of the chaincode! */ -export const handleError = (transactionId: string, err: Error): Error => { - // This regex needs to match the following error messages: - // "the asset %s already exists" - // "The asset ${id} already exists" - // "Asset %s already exists" - const assetAlreadyExistsRegex = /([tT]he )?[aA]sset \w* already exists/g; - const assetAlreadyExistsMatch = err.message.match(assetAlreadyExistsRegex); - logger.debug( - { message: err.message, result: assetAlreadyExistsMatch }, - 'Checking for asset already exists message' - ); - if (assetAlreadyExistsMatch) { - return new AssetExistsError(assetAlreadyExistsMatch[0], transactionId); - } +export const handleError = (transactionId: string, err: unknown): Error => { + logger.debug({ transactionId: transactionId, err }, 'Processing error'); - // This regex needs to match the following error messages: - // "the asset %s does not exist" - // "The asset ${id} does not exist" - // "Asset %s does not exist" - const assetDoesNotExistRegex = /([tT]he )?[aA]sset \w* does not exist/g; - const assetDoesNotExistMatch = err.message.match(assetDoesNotExistRegex); - logger.debug( - { message: err.message, result: assetDoesNotExistMatch }, - 'Checking for asset does not exist message' - ); - if (assetDoesNotExistMatch) { - return new AssetNotFoundError(assetDoesNotExistMatch[0], transactionId); - } + if (isErrorLike(err)) { + const assetAlreadyExistsMatch = matchAssetAlreadyExistsMessage(err.message); + if (assetAlreadyExistsMatch !== null) { + return new AssetExistsError(assetAlreadyExistsMatch, transactionId); + } - // This regex needs to match the following error messages: - // "Failed to get transaction with id %s, error Entry not found in index" - const transactionDoesNotExistRegex = - /Failed to get transaction with id [^,]*, error Entry not found in index/g; - const transactionDoesNotExistMatch = err.message.match( - transactionDoesNotExistRegex - ); - logger.debug( - { message: err.message, result: transactionDoesNotExistMatch }, - 'Checking for transaction does not exist message' - ); - if (transactionDoesNotExistMatch) { - return new TransactionNotFoundError( - transactionDoesNotExistMatch[0], - transactionId + const assetDoesNotExistMatch = matchAssetDoesNotExistMessage(err.message); + if (assetDoesNotExistMatch !== null) { + return new AssetNotFoundError(assetDoesNotExistMatch, transactionId); + } + + const transactionDoesNotExistMatch = matchTransactionDoesNotExistMessage( + err.message ); + if (transactionDoesNotExistMatch !== null) { + return new TransactionNotFoundError( + transactionDoesNotExistMatch, + transactionId + ); + } + + return err; } - logger.error( - { transactionId: transactionId, error: err }, - 'Unhandled transaction error' - ); - return new TransactionError('Transaction error', transactionId); + return new Error(`Unhandled error: ${err}`); }; diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts index a551dac9..34e6f2f0 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -10,69 +10,49 @@ import { evatuateTransaction, submitTransaction, getBlockHeight, - startRetryLoop, - blockEventHandler, + getTransactionValidationCode, + processSubmitTransactionJob, } from './fabric'; import * as config from './config'; import { AssetExistsError, AssetNotFoundError, - TransactionError, TransactionNotFoundError, } from './errors'; import { - BlockEvent, Contract, Gateway, GatewayOptions, Network, Transaction, - TransactionEvent, Wallet, } from 'fabric-network'; import * as fabricProtos from 'fabric-protos'; import { MockProxy, mock } from 'jest-mock-extended'; -import IORedis, { Redis } from 'ioredis'; import Long from 'long'; +import { Job } from 'bullmq'; jest.mock('./config'); +jest.mock('fabric-network', () => { + type FabricNetworkModule = jest.Mocked; + const originalModule: FabricNetworkModule = + jest.requireActual('fabric-network'); + const mockModule: FabricNetworkModule = + jest.createMockFromModule('fabric-network'); + + return { + __esModule: true, + ...mockModule, + Wallets: originalModule.Wallets, + }; +}); jest.mock('ioredis', () => require('ioredis-mock/jest')); describe('Fabric', () => { - const mockTransactionId = - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - const mockKey = `txn:${mockTransactionId}`; - const mockMspId = 'Org1MSP'; - const mockState = Buffer.from( - `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${mockTransactionId}` - ); - const mockArgs = '["test111","red",400,"Jean",101]'; - const mockTimestamp = 1628078044362; - - const addMockTransationDetails = async (redis: Redis) => { - await redis - .multi() - .hset( - mockKey, - 'mspId', - mockMspId, - 'state', - mockState, - 'args', - mockArgs, - 'timestamp', - mockTimestamp, - 'retries', - '0' - ) - .zadd('index:txn:timestamp', mockTimestamp, mockTransactionId) - .exec(); - }; - describe('createWallet', () => { it('creates a wallet containing identities for both orgs', async () => { const wallet = await createWallet(); @@ -137,162 +117,130 @@ describe('Fabric', () => { }); }); - describe('startRetryLoop', () => { - let redis: Redis; + describe('processSubmitTransactionJob', () => { + const mockContracts = new Map(); + const mockPayload = Buffer.from('MOCK PAYLOAD'); + const mockSavedState = Buffer.from('MOCK SAVED STATE'); let mockTransaction: MockProxy; let mockContract: MockProxy; - let mockContracts: Map; - - const flushPromises = () => { - jest.useRealTimers(); - return new Promise((resolve) => setImmediate(resolve)); - }; + let mockJob: MockProxy; beforeEach(() => { - const redisOptions = { - port: config.redisPort, - host: config.redisHost, - username: config.redisUsername, - password: config.redisPassword, + mockTransaction = mock(); + mockTransaction.getTransactionId.mockReturnValue('mockTransactionId'); + + mockContract = mock(); + mockContract.createTransaction + .calledWith('txn') + .mockReturnValue(mockTransaction); + mockContract.deserializeTransaction + .calledWith(mockSavedState) + .mockReturnValue(mockTransaction); + mockContracts.set('mockMspid', mockContract); + + mockJob = mock(); + }); + + it('gets job result with no error or payload if no contract is available for the required mspid', async () => { + mockJob.data = { + mspid: 'missingMspid', }; - redis = new IORedis(redisOptions) as unknown as Redis; + const jobResult = await processSubmitTransactionJob( + mockContracts, + mockJob + ); - mockTransaction = mock(); + expect(jobResult).toStrictEqual({ + transactionError: undefined, + transactionPayload: undefined, + }); + }); + + it('gets a job result containing a payload if the transaction was successful first time', async () => { + mockJob.data = { + mspid: 'mockMspid', + transactionName: 'txn', + transactionArgs: ['arg1', 'arg2'], + }; mockTransaction.submit - .mockResolvedValue(Buffer.from('MOCK PAYLOAD')) - .mockName('submit'); - mockContract = mock(); - mockContract.deserializeTransaction.mockReturnValue(mockTransaction); - mockContracts = new Map(); - mockContracts.set(mockMspId, mockContract); + .calledWith('arg1', 'arg2') + .mockResolvedValue(mockPayload); - jest.useFakeTimers(); - }); - - afterEach(() => { - jest.useRealTimers(); - }); - - it('starts a retry loop which does nothing if there are no saved transaction details', async () => { - const getContractSpy = jest.spyOn(mockContracts, 'get'); - - startRetryLoop(mockContracts, redis); - jest.runOnlyPendingTimers(); - await flushPromises(); - - expect(getContractSpy).not.toBeCalled(); - }); - - it('starts a retry loop which clears the saved details after succesfully retrying a transaction', async () => { - addMockTransationDetails(redis); - - startRetryLoop(mockContracts, redis); - jest.runOnlyPendingTimers(); - await flushPromises(); - - expect(mockContract.deserializeTransaction).toBeCalledWith(mockState); - expect(mockTransaction.submit).toBeCalledWith( - 'test111', - 'red', - 400, - 'Jean', - 101 + const jobResult = await processSubmitTransactionJob( + mockContracts, + mockJob ); - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([]); + expect(jobResult).toStrictEqual({ + transactionError: undefined, + transactionPayload: Buffer.from('MOCK PAYLOAD'), + }); }); - it('starts a retry loop which increments the retry count when a transaction fails', async () => { - addMockTransationDetails(redis); - mockTransaction.submit.mockRejectedValue(new Error('MOCK ERROR')); + it('gets a job result containing a payload if the transaction was successfully rerun using saved transaction state', async () => { + mockJob.data = { + mspid: 'mockMspid', + transactionName: 'txn', + transactionArgs: ['arg1', 'arg2'], + transactionState: mockSavedState, + }; + mockTransaction.submit + .calledWith('arg1', 'arg2') + .mockResolvedValue(mockPayload); - startRetryLoop(mockContracts, redis); - jest.runOnlyPendingTimers(); - await flushPromises(); - - expect(mockContract.deserializeTransaction).toBeCalledWith(mockState); - expect(mockTransaction.submit).toBeCalledWith( - 'test111', - 'red', - 400, - 'Jean', - 101 + const jobResult = await processSubmitTransactionJob( + mockContracts, + mockJob ); - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([ - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95', - ]); - - const savedTransaction = await (redis as Redis).hgetall(mockKey); - expect(savedTransaction.retries).toBe('1'); + expect(jobResult).toStrictEqual({ + transactionError: undefined, + transactionPayload: Buffer.from('MOCK PAYLOAD'), + }); }); - it('starts a retry loop which clears the saved details when a transaction fails as a duplicate', async () => { - addMockTransationDetails(redis); - const mockDuplicateTransactionError = new Error('MOCK ERROR'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockDuplicateTransactionError as any).errors = [ - { - endorsements: [ - { - details: 'duplicate transaction found', - }, - ], - }, - ]; - mockTransaction.submit.mockRejectedValue(mockDuplicateTransactionError); + it('gets a job result containing an error message if the transaction fails but cannot be retried', async () => { + mockJob.data = { + mspid: 'mockMspid', + transactionName: 'txn', + transactionArgs: ['arg1', 'arg2'], + transactionState: mockSavedState, + }; + mockTransaction.submit + .calledWith('arg1', 'arg2') + .mockRejectedValue( + new Error( + 'Failed to get transaction with id txn, error Entry not found in index' + ) + ); - startRetryLoop(mockContracts, redis); - jest.runOnlyPendingTimers(); - await flushPromises(); - - expect(mockContract.deserializeTransaction).toBeCalledWith(mockState); - expect(mockTransaction.submit).toBeCalledWith( - 'test111', - 'red', - 400, - 'Jean', - 101 + const jobResult = await processSubmitTransactionJob( + mockContracts, + mockJob ); - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([]); + expect(jobResult).toStrictEqual({ + transactionError: + 'TransactionNotFoundError: Failed to get transaction with id txn, error Entry not found in index', + transactionPayload: undefined, + }); }); - it('starts a retry loop which clears the saved details when a transaction fails the final attempt', async () => { - addMockTransationDetails(redis); - await (redis as Redis).hincrby(mockKey, 'retries', 5); - mockTransaction.submit.mockRejectedValue(new Error('MOCK ERROR')); + it('throws an error if the transaction fails but can be retried', async () => { + mockJob.data = { + mspid: 'mockMspid', + transactionName: 'txn', + transactionArgs: ['arg1', 'arg2'], + transactionState: mockSavedState, + }; + mockTransaction.submit + .calledWith('arg1', 'arg2') + .mockRejectedValue(new Error('MOCK ERROR')); - startRetryLoop(mockContracts, redis); - jest.runOnlyPendingTimers(); - await flushPromises(); - - expect(mockContract.deserializeTransaction).toBeCalledWith(mockState); - expect(mockTransaction.submit).toBeCalledWith( - 'test111', - 'red', - 400, - 'Jean', - 101 - ); - - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([]); - }); - - it('starts a retry loop which clears the saved details when no contract exist for the org', async () => { - addMockTransationDetails(redis); - mockContracts = new Map(); - startRetryLoop(mockContracts, redis); - jest.runOnlyPendingTimers(); - await flushPromises(); - - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([]); + await expect(async () => { + await processSubmitTransactionJob(mockContracts, mockJob); + }).rejects.toThrow('MOCK ERROR'); }); }); @@ -352,96 +300,65 @@ describe('Fabric', () => { }).rejects.toThrow(TransactionNotFoundError); }); - it('throws a TransactionError for other errors', async () => { + it('throws an Error for other errors', async () => { mockTransaction.evaluate.mockRejectedValue(new Error('MOCK ERROR')); - await expect(async () => { await evatuateTransaction(mockContract, 'txn', 'arga', 'argb'); - }).rejects.toThrow(TransactionError); + }).rejects.toThrow(Error); }); }); describe('submitTransaction', () => { - let redis: Redis; - const mockPayload = Buffer.from('MOCK PAYLOAD'); let mockTransaction: MockProxy; - let mockContract: MockProxy; - - beforeEach(async () => { - const redisOptions = { - port: config.redisPort, - host: config.redisHost, - username: config.redisUsername, - password: config.redisPassword, - }; - - redis = new IORedis(redisOptions) as unknown as Redis; + beforeEach(() => { mockTransaction = mock(); - mockTransaction.submit.mockResolvedValue(mockPayload); - mockTransaction.getTransactionId.mockReturnValue('MOCK TXN ID'); - mockTransaction.serialize.mockReturnValue(Buffer.from('MOCK TXN STATE')); - mockContract = mock(); - mockContract.createTransaction - .calledWith('txn') - .mockReturnValue(mockTransaction); }); - it('gets the transaction ID of the submitted transaction', async () => { + it('gets the result of submitting a transaction', async () => { + const mockPayload = Buffer.from('MOCK PAYLOAD'); + mockTransaction.submit.mockResolvedValue(mockPayload); + const result = await submitTransaction( - mockContract, - redis, - 'mspid', + mockTransaction, 'txn', 'arga', 'argb' ); - expect(result).toBe('MOCK TXN ID'); + expect(result.toString()).toBe(mockPayload.toString()); }); - it.each([ - 'the asset GOCHAINCODE already exists', - 'Asset JAVACHAINCODE already exists', - 'The asset JSCHAINCODE already exists', - ])( - 'throws an AssetExistsError an asset already exists error occurs: %s', - async (msg) => { - mockTransaction.submit.mockRejectedValue(new Error(msg)); + it('throws an AssetExistsError an asset already exists error occurs', async () => { + mockTransaction.submit.mockRejectedValue( + new Error('The asset JSCHAINCODE already exists') + ); - await expect(async () => { - await submitTransaction( - mockContract, - redis, - 'mspid', - 'txn', - 'arga', - 'argb' - ); - }).rejects.toThrow(AssetExistsError); - } - ); + await expect(async () => { + await submitTransaction( + mockTransaction, + 'mspid', + 'txn', + 'arga', + 'argb' + ); + }).rejects.toThrow(AssetExistsError); + }); - it.each([ - 'the asset GOCHAINCODE does not exist', - 'Asset JAVACHAINCODE does not exist', - 'The asset JSCHAINCODE does not exist', - ])( - 'throws an AssetNotFoundError if an asset does not exist error occurs: %s', - async (msg) => { - mockTransaction.submit.mockRejectedValue(new Error(msg)); + it('throws an AssetNotFoundError if an asset does not exist error occurs', async () => { + mockTransaction.submit.mockRejectedValue( + new Error('The asset JSCHAINCODE does not exist') + ); - await expect(async () => { - await submitTransaction( - mockContract, - redis, - 'mspid', - 'txn', - 'arga', - 'argb' - ); - }).rejects.toThrow(AssetNotFoundError); - } - ); + await expect(async () => { + await submitTransaction( + mockTransaction, + 'mspid', + 'txn', + 'arga', + 'argb' + ); + }).rejects.toThrow(AssetNotFoundError); + }); it('throws a TransactionNotFoundError if a transaction not found error occurs', async () => { mockTransaction.submit.mockRejectedValue( @@ -452,8 +369,7 @@ describe('Fabric', () => { await expect(async () => { await submitTransaction( - mockContract, - redis, + mockTransaction, 'mspid', 'txn', 'arga', @@ -462,76 +378,42 @@ describe('Fabric', () => { }).rejects.toThrow(TransactionNotFoundError); }); - it('throws a TransactionError for other errors', async () => { + it('throws an Error for other errors', async () => { mockTransaction.submit.mockRejectedValue(new Error('MOCK ERROR')); await expect(async () => { await submitTransaction( - mockContract, - redis, + mockTransaction, 'mspid', 'txn', 'arga', 'argb' ); - }).rejects.toThrow(TransactionError); + }).rejects.toThrow(Error); }); }); - describe('blockEventHandler', () => { - let redis: Redis; - let mockIsValidGetter: jest.Mock; - let mockTransactionIdGetter: jest.Mock; - let mockTransactionEvent: MockProxy; - let mockBlockEvent: MockProxy; + describe('getTransactionValidationCode', () => { + it('gets the validation code from a processed transaction', async () => { + const processedTransactionProto = + fabricProtos.protos.ProcessedTransaction.create(); + processedTransactionProto.validationCode = + fabricProtos.protos.TxValidationCode.VALID; + const processedTransactionBuffer = Buffer.from( + fabricProtos.protos.ProcessedTransaction.encode( + processedTransactionProto + ).finish() + ); - beforeEach(async () => { - const redisOptions = { - port: config.redisPort, - host: config.redisHost, - username: config.redisUsername, - password: config.redisPassword, - }; - - redis = new IORedis(redisOptions) as unknown as Redis; - addMockTransationDetails(redis); - - const baseMock = {}; - mockTransactionEvent = mock(baseMock); - mockIsValidGetter = jest.fn(); - Object.defineProperty(baseMock, 'isValid', { get: mockIsValidGetter }); - mockTransactionIdGetter = jest.fn(); - Object.defineProperty(baseMock, 'transactionId', { - get: mockTransactionIdGetter, - }); - - mockBlockEvent = mock(); - mockBlockEvent.getTransactionEvents.mockReturnValue([ - mockTransactionEvent, - ]); - }); - - it('clears saved details for valid transactions', async () => { - const blockListener = blockEventHandler(redis); - mockIsValidGetter.mockReturnValue(true); - mockTransactionIdGetter.mockReturnValue(mockTransactionId); - - await blockListener(mockBlockEvent); - - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([]); - }); - - it('does not clear saved details for invalid transactions', async () => { - const blockListener = blockEventHandler(redis); - mockIsValidGetter.mockReturnValue(false); - - await blockListener(mockBlockEvent); - - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([ - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95', - ]); + const mockTransaction = mock(); + mockTransaction.evaluate.mockResolvedValue(processedTransactionBuffer); + const mockContract = mock(); + mockContract.createTransaction + .calledWith('GetTransactionByID') + .mockReturnValue(mockTransaction); + expect(await getTransactionValidationCode(mockContract, 'txn1')).toBe( + 'VALID' + ); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index aa8586ea..70a3a6f2 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -10,23 +10,20 @@ import { GatewayOptions, Wallets, Network, - BlockListener, - BlockEvent, - TransactionEvent, + TimeoutError, + Transaction, Wallet, } from 'fabric-network'; -import { Redis } from 'ioredis'; import * as config from './config'; import { logger } from './logger'; import { - storeTransactionDetails, - getRetryTransactionDetails, - clearTransactionDetails, - incrementRetryCount, - TransactionDetails, -} from './redis'; -import { handleError, isDuplicateTransactionError } from './errors'; -import protos from 'fabric-protos'; + handleError, + isContractError, + isDuplicateTransactionError, +} from './errors'; +import * as protos from 'fabric-protos'; +import { Job } from 'bullmq'; +import { JobData, JobResult, updateJobData } from './jobs'; /* * Creates an in memory wallet to hold credentials for an Org1 and Org2 user @@ -124,55 +121,119 @@ export const getContracts = async ( }; /* - * Starts a timer to retry transactions at regular intervals + * Process a submit transaction request from the job queue * - * Note: there is check for whether the transaction has successfully completed - * since it could succeed between any check and the retry, so the additional - * transaction to get the status is unlikely to be worthwhile + * For this sample transactions are retried if they fail with any error, + * except for errors from the smart contract, or duplicate transaction + * errors + * + * You might decide to retry transactions which fail with specific errors + * instead, for example: + * MVCC_READ_CONFLICT + * PHANTOM_READ_CONFLICT + * ENDORSEMENT_POLICY_FAILURE + * CHAINCODE_VERSION_CONFLICT + * EXPIRED_CHAINCODE */ -export const startRetryLoop = ( +export const processSubmitTransactionJob = async ( contracts: Map, - redis: Redis -): void => { - const retryInterval = setInterval( - async (contracts, redis) => { - if (logger.isLevelEnabled('debug')) { - try { - const pendingTransactionCount = await (redis as Redis).zcard( - 'index:txn:timestamp' - ); - logger.debug( - '%d transactions awaiting retry', - pendingTransactionCount - ); - } catch (err) { - logger.warn({ err }, 'Error getting pending transaction count'); - } + job: Job +): Promise => { + logger.debug({ jobId: job.id, jobName: job.name }, 'Processing job'); + + const contract = contracts.get(job.data.mspid); + if (contract === undefined) { + logger.error( + { jobId: job.id, jobName: job.name }, + 'Contract not found for MSP ID %s', + job.data.mspid + ); + + // Retrying will not work, so give up with an unsuccessful result + return { + transactionError: undefined, + transactionPayload: undefined, + }; + } + + let transaction: Transaction; + if (job.data.transactionState) { + const savedState = job.data.transactionState; + logger.debug( + { + jobId: job.id, + jobName: job.name, + savedState, + }, + 'Using previously saved transaction state' + ); + + transaction = contract.deserializeTransaction(savedState); + } else { + logger.debug( + { + jobId: job.id, + jobName: job.name, + }, + 'Using new transaction' + ); + + transaction = contract.createTransaction(job.data.transactionName); + await updateJobData(job, transaction); + } + + try { + logger.debug( + { + jobId: job.id, + jobName: job.name, + transactionId: transaction.getTransactionId(), + }, + 'Submitting transaction' + ); + const args = job.data.transactionArgs; + const payload = await submitTransaction(transaction, ...args); + + return { + transactionError: undefined, + transactionPayload: payload, + }; + } catch (err) { + if ( + err instanceof Error && + (isContractError(err) || isDuplicateTransactionError(err)) + ) { + logger.error( + { jobId: job.id, jobName: job.name, err }, + 'Fatal transaction error occurred' + ); + + // Return a job result to stop retrying + return { + transactionError: err.toString(), + transactionPayload: undefined, + }; + } else { + logger.warn( + { jobId: job.id, jobName: job.name, err }, + 'Retryable transaction error occurred' + ); + + // The original transaction may eventually get committed in the case of + // a timeout error, so keep the same transaction ID to protect against + // unintended duplicate transactions + if (!(err instanceof TimeoutError)) { + logger.debug( + { jobId: job.id, jobName: job.name }, + 'Clearing saved transaction state' + ); + await updateJobData(job, undefined); } - const savedTransaction = await getRetryTransactionDetails(redis); - - if (savedTransaction) { - const contract = contracts.get(savedTransaction.mspId); - - if (contract) { - await retryTransaction(contract, redis, savedTransaction); - } else { - clearTransactionDetails(redis, savedTransaction.transactionId); - logger.error( - 'No contract found for %s to retry transaction %s', - savedTransaction.mspId, - savedTransaction.transactionId - ); - } - } - }, - config.retryDelay, - contracts, - redis - ); - - retryInterval.unref(); + // Rethrow the error to keep retrying + throw err; + } + } }; /* @@ -183,146 +244,64 @@ export const evatuateTransaction = async ( transactionName: string, ...transactionArgs: string[] ): Promise => { - const txn = contract.createTransaction(transactionName); - const txnId = txn.getTransactionId(); + const transaction = contract.createTransaction(transactionName); + const transactionId = transaction.getTransactionId(); + logger.trace({ transaction }, 'Evaluating transaction'); try { - const payload = await txn.evaluate(...transactionArgs); - logger.debug( - { transactionId: txnId, payload: payload.toString() }, + const payload = await transaction.evaluate(...transactionArgs); + logger.trace( + { transactionId: transactionId, payload: payload.toString() }, 'Evaluate transaction response received' ); return payload; + } catch (err) { + throw handleError(transactionId, err); + } +}; + +/* + * Submit a transaction and handle any errors + */ +export const submitTransaction = async ( + transaction: Transaction, + ...transactionArgs: string[] +): Promise => { + logger.trace({ transaction }, 'Submitting transaction'); + const txnId = transaction.getTransactionId(); + + try { + const payload = await transaction.submit(...transactionArgs); + logger.trace( + { transactionId: txnId, payload: payload.toString() }, + 'Submit transaction response received' + ); + return payload; } catch (err) { throw handleError(txnId, err); } }; /* - * Submit a transaction and handle any errors - * - * Transaction details are saved before being submitted so that they can be - * retried if any errors occur + * Get the validation code of the specified transaction */ -export const submitTransaction = async ( - contract: Contract, - redis: Redis, - mspId: string, - transactionName: string, - ...transactionArgs: string[] +export const getTransactionValidationCode = async ( + qsccContract: Contract, + transactionId: string ): Promise => { - const txn = contract.createTransaction(transactionName); - const txnId = txn.getTransactionId(); - const txnState = txn.serialize(); - const txnArgs = JSON.stringify(transactionArgs); - const timestamp = Date.now(); + const data = await evatuateTransaction( + qsccContract, + 'GetTransactionByID', + config.channelName, + transactionId + ); - try { - // Store the transaction details and set the event handler in case there - // are problems later with commiting the transaction - await storeTransactionDetails( - redis, - txnId, - mspId, - txnState, - txnArgs, - timestamp - ); - txn.setEventHandler(DefaultEventHandlerStrategies.NONE); - await txn.submit(...transactionArgs); - } catch (err) { - // If the transaction failed to endorse, there is no point attempting - // to retry it later so clear the transaction details - // TODO will this always catch endorsement errors or can they - // arrive later? - await clearTransactionDetails(redis, txnId); - throw handleError(txnId, err); - } + const processedTransaction = protos.protos.ProcessedTransaction.decode(data); + const validationCode = + protos.protos.TxValidationCode[processedTransaction.validationCode]; - return txnId; -}; - -/* - * Retry a transaction - * - * The saved transaction details include a retry count which is used to ensure - * failing transactions are not retried indefinitely - */ -const retryTransaction = async ( - contract: Contract, - redis: Redis, - savedTransaction: TransactionDetails -): Promise => { - logger.debug('Retrying transaction %s', savedTransaction.transactionId); - - try { - const transaction = contract.deserializeTransaction( - savedTransaction.transactionState - ); - const args: string[] = JSON.parse(savedTransaction.transactionArgs); - - const payload = await transaction.submit(...args); - logger.debug( - { - transactionId: savedTransaction.transactionId, - payload: payload.toString(), - }, - 'Retry transaction response received' - ); - - await clearTransactionDetails(redis, savedTransaction.transactionId); - } catch (err) { - if (isDuplicateTransactionError(err)) { - logger.warn( - 'Transaction %s has already been committed', - savedTransaction.transactionId - ); - await clearTransactionDetails(redis, savedTransaction.transactionId); - } else { - logger.warn( - err, - 'Retry %d failed for transaction %s', - savedTransaction.retries, - savedTransaction.transactionId - ); - - if (savedTransaction.retries < config.maxRetryCount) { - await incrementRetryCount(redis, savedTransaction.transactionId); - } else { - await clearTransactionDetails(redis, savedTransaction.transactionId); - } - } - } -}; - -/* - * Block event listener to handle successful transactions - * - * Transaction details are saved before being submitted so that they can be - * retried, and this listener deletes those transaction details for any - * successful transactions - * - * Transactions can be submitted using one of two identities however one one - * of those identities is used to listen for block events - */ -export const blockEventHandler = (redis: Redis): BlockListener => { - const blockListener = async (event: BlockEvent) => { - logger.debug( - { blockNumber: event.blockNumber.toString() }, - 'Block event received' - ); - const transactionEvents: Array = - event.getTransactionEvents(); - - for (const event of transactionEvents) { - if (event && event.isValid) { - logger.debug('Remove transation with txnId %s', event.transactionId); - await clearTransactionDetails(redis, event.transactionId); - } - } - }; - - return blockListener; + logger.debug({ transactionId }, 'Validation code: %s', validationCode); + return validationCode; }; /* @@ -340,6 +319,7 @@ export const getBlockHeight = async ( ); const info = protos.common.BlockchainInfo.decode(data); const blockHeight = info.height; + logger.debug('Current block height: %d', blockHeight); return blockHeight; }; diff --git a/asset-transfer-basic/rest-api-typescript/src/health.router.ts b/asset-transfer-basic/rest-api-typescript/src/health.router.ts index 27b40c3d..463ee0e4 100644 --- a/asset-transfer-basic/rest-api-typescript/src/health.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/health.router.ts @@ -8,6 +8,8 @@ import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import { getBlockHeight } from './fabric'; import { logger } from './logger'; import * as config from './config'; +import { Queue } from 'bullmq'; +import { getJobCounts } from './jobs'; const { SERVICE_UNAVAILABLE, OK } = StatusCodes; @@ -27,21 +29,26 @@ healthRouter.get('/ready', (_req, res: Response) => healthRouter.get('/live', async (req: Request, res: Response) => { logger.debug(req.body, 'Liveness request received'); - const qsccOrg1 = req.app.get(config.mspIdOrg1).qsccContract as Contract; - const qsccOrg2 = req.app.get(config.mspIdOrg2).qsccContract as Contract; - try { - await Promise.all([getBlockHeight(qsccOrg1), getBlockHeight(qsccOrg2)]); - } catch (err) { - logger.error(err, 'Error processing liveness request'); + const submitQueue = req.app.get('jobq') as Queue; + const qsccOrg1 = req.app.get(config.mspIdOrg1).qsccContract as Contract; + const qsccOrg2 = req.app.get(config.mspIdOrg2).qsccContract as Contract; - res.status(SERVICE_UNAVAILABLE).json({ + await Promise.all([ + getBlockHeight(qsccOrg1), + getBlockHeight(qsccOrg2), + getJobCounts(submitQueue), + ]); + } catch (err) { + logger.error({ err }, 'Error processing liveness request'); + + return res.status(SERVICE_UNAVAILABLE).json({ status: getReasonPhrase(SERVICE_UNAVAILABLE), timestamp: new Date().toISOString(), }); } - res.status(OK).json({ + return res.status(OK).json({ status: getReasonPhrase(OK), timestamp: new Date().toISOString(), }); diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 98f91ebc..567d3cbc 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -2,19 +2,93 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { Contract } from 'fabric-network'; import * as config from './config'; +import { + createGateway, + createWallet, + getContracts, + getNetwork, +} from './fabric'; +import { + initJobQueue, + initJobQueueScheduler, + initJobQueueWorker, +} from './jobs'; import { logger } from './logger'; import { createServer } from './server'; +import { isMaxmemoryPolicyNoeviction } from './redis'; +import { Queue, QueueScheduler, Worker } from 'bullmq'; + +let jobQueue: Queue | undefined; +let jobQueueWorker: Worker | undefined; +let jobQueueScheduler: QueueScheduler | undefined; async function main() { + logger.info('Checking Redis config'); + if (!(await isMaxmemoryPolicyNoeviction())) { + throw new Error( + 'Invalid redis configuration: redis instance must have the setting maxmemory-policy=noeviction' + ); + } + + logger.info('Connecting to Fabric network'); + const wallet = await createWallet(); + + const gatewayOrg1 = await createGateway( + config.connectionProfileOrg1, + config.mspIdOrg1, + wallet + ); + const networkOrg1 = await getNetwork(gatewayOrg1); + const contractsOrg1 = await getContracts(networkOrg1); + + const gatewayOrg2 = await createGateway( + config.connectionProfileOrg2, + config.mspIdOrg2, + wallet + ); + const networkOrg2 = await getNetwork(gatewayOrg2); + const contractsOrg2 = await getContracts(networkOrg2); + + const assetContracts = new Map(); + assetContracts.set(config.mspIdOrg1, contractsOrg1.assetContract); + assetContracts.set(config.mspIdOrg2, contractsOrg2.assetContract); + + logger.info('Initialising submit job queue'); + jobQueue = initJobQueue(); + jobQueueWorker = initJobQueueWorker(assetContracts); + if (config.submitJobQueueScheduler === true) { + logger.info('Initialising submit job queue scheduler'); + jobQueueScheduler = initJobQueueScheduler(); + } + + logger.info('Creating REST server'); const app = await createServer(); + app.set(config.mspIdOrg1, contractsOrg1); + app.set(config.mspIdOrg2, contractsOrg2); + app.set('jobq', jobQueue); app.listen(config.port, () => { - logger.info('Express server started on port: %d', config.port); + logger.info('REST server started on port: %d', config.port); }); } -// TODO handle errors! E.g. try starting with the wrong cert and private key! -main().catch((err) => { - logger.error(err, 'Unxepected error'); +main().catch(async (err) => { + logger.error({ err }, 'Unxepected error'); + + if (jobQueueScheduler != undefined) { + logger.debug('Closing job queue scheduler'); + await jobQueueScheduler.close(); + } + + if (jobQueueWorker != undefined) { + logger.debug('Closing job queue worker'); + await jobQueueWorker.close(); + } + + if (jobQueue != undefined) { + logger.debug('Closing job queue'); + await jobQueue.close(); + } }); diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts new file mode 100644 index 00000000..097d19a7 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Queue } from 'bullmq'; +import express, { Request, Response } from 'express'; +import { getReasonPhrase, StatusCodes } from 'http-status-codes'; +import { JobNotFoundError } from './errors'; +import { getJobSummary } from './jobs'; +import { logger } from './logger'; + +const { INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; + +export const jobsRouter = express.Router(); + +jobsRouter.get('/:jobId', async (req: Request, res: Response) => { + const jobId = req.params.jobId; + logger.debug('Read request received for job ID %s', jobId); + + try { + const submitQueue = req.app.get('jobq') as Queue; + + const jobSummary = await getJobSummary(submitQueue, jobId); + + return res.status(OK).json(jobSummary); + } catch (err) { + logger.error({ err }, 'Error processing read request for job ID %s', jobId); + + if (err instanceof JobNotFoundError) { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts new file mode 100644 index 00000000..05fe6af0 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts @@ -0,0 +1,155 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Job, Queue } from 'bullmq'; +import { getJobCounts, getJobSummary } from './jobs'; +import { mock, MockProxy } from 'jest-mock-extended'; +import { JobNotFoundError } from './errors'; + +describe('initJobQueue', () => { + it.todo('write tests'); +}); + +describe('initJobQueueWorker', () => { + it.todo('write tests'); +}); + +describe('initJobQueueScheduler', () => { + it.todo('write tests'); +}); + +describe('addSubmitTransactionJob', () => { + it.todo('write tests'); +}); + +describe('getJobSummary', () => { + let mockQueue: MockProxy; + let mockJob: MockProxy; + + beforeEach(() => { + mockQueue = mock(); + mockJob = mock(); + }); + + it('throws a JobNotFoundError if the Job is undefined', async () => { + mockQueue.getJob.calledWith('1').mockResolvedValue(undefined); + + await expect(async () => { + await getJobSummary(mockQueue, '1'); + }).rejects.toThrow(JobNotFoundError); + }); + + it('gets a job summary with transaction payload data', async () => { + mockQueue.getJob.calledWith('1').mockResolvedValue(mockJob); + mockJob.id = '1'; + mockJob.data = { + transactionIds: ['txn1'], + }; + mockJob.returnvalue = { + transactionPayload: Buffer.from('MOCK PAYLOAD'), + }; + + expect(await getJobSummary(mockQueue, '1')).toStrictEqual({ + jobId: '1', + transactionIds: ['txn1'], + transactionError: undefined, + transactionPayload: 'MOCK PAYLOAD', + }); + }); + + it('gets a job summary with empty transaction payload data', async () => { + mockQueue.getJob.calledWith('1').mockResolvedValue(mockJob); + mockJob.id = '1'; + mockJob.data = { + transactionIds: ['txn1'], + }; + mockJob.returnvalue = { + transactionPayload: Buffer.from(''), + }; + + expect(await getJobSummary(mockQueue, '1')).toStrictEqual({ + jobId: '1', + transactionIds: ['txn1'], + transactionError: undefined, + transactionPayload: '', + }); + }); + + it('gets a job summary with a transaction error', async () => { + mockQueue.getJob.calledWith('1').mockResolvedValue(mockJob); + mockJob.id = '1'; + mockJob.data = { + transactionIds: ['txn1'], + }; + mockJob.returnvalue = { + transactionError: 'MOCK ERROR', + }; + + expect(await getJobSummary(mockQueue, '1')).toStrictEqual({ + jobId: '1', + transactionIds: ['txn1'], + transactionError: 'MOCK ERROR', + transactionPayload: '', + }); + }); + + it('gets a job summary when there is no return value', async () => { + mockQueue.getJob.calledWith('1').mockResolvedValue(mockJob); + mockJob.id = '1'; + mockJob.returnvalue = undefined; + mockJob.data = { + transactionIds: ['txn1'], + }; + + expect(await getJobSummary(mockQueue, '1')).toStrictEqual({ + jobId: '1', + transactionIds: ['txn1'], + transactionError: undefined, + transactionPayload: undefined, + }); + }); + + it('gets a job summary when there is no job data', async () => { + mockQueue.getJob.calledWith('1').mockResolvedValue(mockJob); + mockJob.id = '1'; + mockJob.data = undefined; + mockJob.returnvalue = { + transactionPayload: Buffer.from('MOCK PAYLOAD'), + }; + + expect(await getJobSummary(mockQueue, '1')).toStrictEqual({ + jobId: '1', + transactionIds: [], + transactionError: undefined, + transactionPayload: 'MOCK PAYLOAD', + }); + }); +}); + +describe('updateSubmitTransactionJobStateData', () => { + it.todo('write tests'); +}); + +describe('getJobCounts', () => { + it('gets job counts from the specified queue', async () => { + const mockQueue = mock(); + mockQueue.getJobCounts + .calledWith('active', 'completed', 'delayed', 'failed', 'waiting') + .mockResolvedValue({ + active: 1, + completed: 2, + delayed: 3, + failed: 4, + waiting: 5, + }); + + expect(await getJobCounts(mockQueue)).toStrictEqual({ + active: 1, + completed: 2, + delayed: 3, + failed: 4, + waiting: 5, + }); + }); +}); diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.ts new file mode 100644 index 00000000..da397a2d --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.ts @@ -0,0 +1,216 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * This sample uses BullMQ jobs to process submit transactions, which includes + * retry support for failing jobs + * + * Important: BullMQ requires the following setting in redis + * maxmemory-policy=noeviction + * For details, see: https://docs.bullmq.io/guide/connections + */ + +import { ConnectionOptions, Job, Queue, QueueScheduler, Worker } from 'bullmq'; +import { Contract, Transaction } from 'fabric-network'; +import * as config from './config'; +import { JobNotFoundError } from './errors'; +import { processSubmitTransactionJob } from './fabric'; +import { logger } from './logger'; + +export type JobData = { + mspid: string; + transactionName: string; + transactionArgs: string[]; + transactionState?: Buffer; + transactionIds: string[]; +}; + +export type JobResult = { + transactionPayload?: Buffer; + transactionError?: string; +}; + +// TODO include attempts made? +export type JobSummary = { + jobId: string; + transactionIds: string[]; + transactionPayload?: string; + transactionError?: string; +}; + +const connection: ConnectionOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, +}; + +export const initJobQueue = (): Queue => { + const submitQueue = new Queue(config.JOB_QUEUE_NAME, { + connection, + defaultJobOptions: { + attempts: config.submitJobAttempts, + backoff: { + type: config.submitJobBackoffType, + delay: config.submitJobBackoffDelay, + }, + removeOnComplete: config.maxCompletedSubmitJobs, + removeOnFail: config.maxFailedSubmitJobs, + }, + }); + + return submitQueue; +}; + +export const initJobQueueWorker = ( + contracts: Map +): Worker => { + const worker = new Worker( + config.JOB_QUEUE_NAME, + async (job): Promise => { + return await processSubmitTransactionJob(contracts, job); + }, + { connection, concurrency: config.submitJobConcurrency } + ); + + worker.on('failed', (job) => { + logger.error({ job }, 'Job failed'); // WHY?! + }); + + // Important: need to handle this error otherwise worker may stop + // processing jobs + worker.on('error', (err) => { + logger.error({ err }, 'Worker error'); + }); + + if (logger.isLevelEnabled('debug')) { + worker.on('completed', (job) => { + logger.debug({ job }, 'Job completed'); + }); + } + + return worker; +}; + +export const initJobQueueScheduler = (): QueueScheduler => { + const queueScheduler = new QueueScheduler(config.JOB_QUEUE_NAME, { + connection, + }); + + queueScheduler.on('failed', (jobId, failedReason) => { + // TODO when does this happen, and how should it be handled? + logger.error({ jobId, failedReason }, 'Queue sceduler failure'); + }); + + return queueScheduler; +}; + +export const addSubmitTransactionJob = async ( + submitQueue: Queue, + mspid: string, + transactionName: string, + ...transactionArgs: string[] +): Promise => { + const jobName = `submit ${transactionName} transaction`; + const job = await submitQueue.add(jobName, { + mspid, + transactionName, + transactionArgs: transactionArgs, + transactionIds: [], + }); + + if (job?.id === undefined) { + throw new Error('Submit transaction job ID not available'); + } + + return job.id; +}; + +/* + * Gets a summary for the jobs endpoint + */ +export const getJobSummary = async ( + queue: Queue, + jobId: string +): Promise => { + const job: Job | undefined = await queue.getJob(jobId); + logger.debug({ job }, 'Got job'); + + if (!(job && job.id != undefined)) { + throw new JobNotFoundError(`Job ${jobId} not found`, jobId); + } + + let transactionIds: string[]; + if (job.data && job.data.transactionIds) { + transactionIds = job.data.transactionIds; + } else { + transactionIds = []; + } + + let transactionError; + let transactionPayload; + const returnValue = job.returnvalue; + if (returnValue) { + if (returnValue.transactionError) { + transactionError = returnValue.transactionError; + } + + if ( + returnValue.transactionPayload && + returnValue.transactionPayload.length > 0 + ) { + transactionPayload = returnValue.transactionPayload.toString(); + } else { + transactionPayload = ''; + } + } + + const jobSummary: JobSummary = { + jobId: job.id, + transactionIds, + transactionError, + transactionPayload, + }; + + return jobSummary; +}; + +export const updateJobData = async ( + job: Job, + transaction: Transaction | undefined +): Promise => { + const newData = { ...job.data }; + + if (transaction != undefined) { + const transationIds = ([] as string[]).concat( + newData.transactionIds, + transaction.getTransactionId() + ); + newData.transactionIds = transationIds; + + newData.transactionState = transaction.serialize(); + } else { + newData.transactionState = undefined; + } + + await job.update(newData); +}; + +/* + * Get the current job counts + * + * This function is used for the liveness REST endpoint + */ +export const getJobCounts = async ( + queue: Queue +): Promise<{ [index: string]: number }> => { + const jobCounts = await queue.getJobCounts( + 'active', + 'completed', + 'delayed', + 'failed', + 'waiting' + ); + logger.debug({ jobCounts }, 'Current job counts'); + + return jobCounts; +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts b/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts index 8b4f291c..a73f3b8c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.spec.ts @@ -2,183 +2,33 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as config from './config'; -import IORedis, { Redis } from 'ioredis'; -import { - clearTransactionDetails, - incrementRetryCount, - storeTransactionDetails, - getTransactionDetails, - getRetryTransactionDetails, -} from './redis'; +import { isMaxmemoryPolicyNoeviction } from './redis'; -jest.mock('ioredis', () => require('ioredis-mock/jest')); +const mockRedisConfig = jest.fn(); +jest.mock('ioredis', () => { + return jest.fn().mockImplementation(() => { + return { + config: mockRedisConfig, + disconnect: jest.fn(), + }; + }); +}); jest.mock('./config'); describe('Redis', () => { - let redis: Redis; - - const mockTransactionId = - '0ae62c01e4c4b112c3f3954a2f11243da76778e46df9ad2783bcbafc79652b95'; - const mockKey = `txn:${mockTransactionId}`; - const mockMspId = 'Org1MSP'; - const mockState = Buffer.from( - `{"name":"CreateAsset","nonce":"damqinq8nrI4n4qY8lFVsZw7RwG2ufrv","transactionId":${mockTransactionId}` - ); - const mockArgs = '["test111","red",400,"Jean",101]'; - const mockTimestamp = 1628078044362; - - const addMockTransationDetails = async (redis: Redis) => { - await redis - .multi() - .hset( - mockKey, - 'mspId', - mockMspId, - 'state', - mockState, - 'args', - mockArgs, - 'timestamp', - mockTimestamp, - 'retries', - '0' - ) - .zadd('index:txn:timestamp', mockTimestamp, mockTransactionId) - .exec(); - }; - - beforeEach(async () => { - const redisOptions = { - port: config.redisPort, - host: config.redisHost, - username: config.redisUsername, - password: config.redisPassword, - }; - - redis = new IORedis(redisOptions) as unknown as Redis; - }); - describe('storeTransactionDetails', () => { - it('stores transaction details as a hash', async () => { - await storeTransactionDetails( - redis, - mockTransactionId, - mockMspId, - mockState, - mockArgs, - mockTimestamp - ); - - const storedTransaction = await redis.hgetall(mockKey); - const expectedTransaction = { - mspId: mockMspId, - state: mockState, - args: mockArgs, - retries: '0', - timestamp: mockTimestamp.toString(), - }; - expect(storedTransaction).toStrictEqual(expectedTransaction); - }); - - it('adds the transaction ID to the sorted set timestamp index', async () => { - await storeTransactionDetails( - redis, - mockTransactionId, - mockMspId, - mockState, - mockArgs, - mockTimestamp - ); - - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([mockTransactionId]); - }); - - // TODO this seems to work for spying/mocking... - // jest.spyOn(redis, 'multi').mock... - // but haven't worked out how to spy on the hset, zadd, exec in that chain - // Ask Mark? - it.todo('handles an error from redis'); + beforeEach(() => { + mockRedisConfig.mockClear(); }); - describe('getTransactionDetails', () => { - it('gets the transaction details from a hash', async () => { - await addMockTransationDetails(redis); - - const details = await getTransactionDetails(redis, mockTransactionId); - - expect(details).toStrictEqual({ - transactionId: mockTransactionId, - mspId: mockMspId, - transactionState: mockState, - transactionArgs: mockArgs, - retries: 0, - timestamp: mockTimestamp, - }); + describe('isMaxmemoryPolicyNoeviction', () => { + it('returns true when the maxmemory-policy is noeviction', async () => { + mockRedisConfig.mockReturnValue(['maxmemory-policy', 'noeviction']); + expect(await isMaxmemoryPolicyNoeviction()).toBe(true); }); - it.todo('handles an error from redis'); - }); - - describe('getRetryTransactionDetails', () => { - it('gets the oldest transaction details from a hash', async () => { - await addMockTransationDetails(redis); - - const details = await getRetryTransactionDetails(redis); - - expect(details).toStrictEqual({ - transactionId: mockTransactionId, - mspId: mockMspId, - transactionState: mockState, - transactionArgs: mockArgs, - retries: 0, - timestamp: mockTimestamp, - }); + it('returns false when the maxmemory-policy is not noeviction', async () => { + mockRedisConfig.mockReturnValue(['maxmemory-policy', 'allkeys-lru']); + expect(await isMaxmemoryPolicyNoeviction()).toBe(false); }); - - it('gets undefined if there are no transactions to retry', async () => { - const details = await getRetryTransactionDetails(redis); - - expect(details).toBeUndefined(); - }); - - it.todo('handles an error from redis'); - }); - - describe('clearTransactionDetails', () => { - it('removes the transaction details hash', async () => { - await addMockTransationDetails(redis); - - await clearTransactionDetails(redis, mockTransactionId); - - const storedTransaction = await redis.hgetall(mockKey); - expect(storedTransaction).not.toHaveProperty('state'); - }); - - it('removes the transaction ID from the sorted set timestamp index', async () => { - await addMockTransationDetails(redis); - - await clearTransactionDetails(redis, mockTransactionId); - - const index = await redis.zrange('index:txn:timestamp', 0, -1); - expect(index).toStrictEqual([]); - }); - }); - - describe('incrementRetryCount', () => { - it('increments the retries value in the transction details hash', async () => { - await addMockTransationDetails(redis); - - await incrementRetryCount(redis, mockTransactionId); - - const retries = await redis.hget(mockKey, 'retries'); - expect(retries).toBe('1'); - }); - - it.todo( - 'updates the position of the transaction ID in the sorted set timestamp index' - ); - - it.todo('handles an error from redis'); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.ts b/asset-transfer-basic/rest-api-typescript/src/redis.ts index fc89fa9b..bb4246da 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.ts @@ -1,12 +1,7 @@ /* * SPDX-License-Identifier: Apache-2.0 * - * This sample includes basic retry logic so it needs somewhere to store - * transaction details in case the app restarts for any reason, and Redis is - * just one of the options available - * - * Note: This implementation is not designed with multiple instances of the - * REST app in mind, which is likely to be required in a production environment + * TBC */ import IORedis, { Redis, RedisOptions } from 'ioredis'; @@ -14,184 +9,43 @@ import IORedis, { Redis, RedisOptions } from 'ioredis'; import * as config from './config'; import { logger } from './logger'; -const redisOptions: RedisOptions = { - port: config.redisPort, - host: config.redisHost, - username: config.redisUsername, - password: config.redisPassword, -}; - -export const redis = new IORedis(redisOptions); - -export type TransactionDetails = { - transactionId: string; - mspId: string; - transactionState: Buffer; - transactionArgs: string; - timestamp: number; - retries: number; -}; - /* - * Store enough information in order to resubmit a transaction + * Check whether the maxmemory-policy config is set to noeviction + * + * BullMQ requires this setting in redis + * For details, see: https://docs.bullmq.io/guide/connections */ -export const storeTransactionDetails = async ( - redis: Redis, - transactionId: string, - mspId: string, - transactionState: Buffer, - transactionArgs: string, - timestamp: number -): Promise => { +export const isMaxmemoryPolicyNoeviction = async (): Promise => { + let redis: Redis | undefined; + + const redisOptions: RedisOptions = { + port: config.redisPort, + host: config.redisHost, + username: config.redisUsername, + password: config.redisPassword, + }; + try { - const key = `txn:${transactionId}`; - logger.debug( - { - key, - mspId, - transactionState, - transactionArgs, - timestamp, - }, - 'Storing transaction details' - ); - await redis - .multi() - .hset( - key, - 'mspId', - mspId, - 'state', - transactionState, - 'args', - transactionArgs, - 'timestamp', - timestamp, - 'retries', - '0' - ) - .zadd('index:txn:timestamp', timestamp, transactionId) - .exec(); - } catch (err) { - // TODO just log?! - logger.error( - { err }, - 'Error storing details for transaction ID %s', - transactionId - ); - } -}; + redis = new IORedis(redisOptions); -/* - * Get the information required to resubmit a transaction - */ -export const getTransactionDetails = async ( - redis: Redis, - transactionId: string -): Promise => { - try { - const savedTransaction = await (redis as Redis).hgetall( - `txn:${transactionId}` - ); - logger.debug( - { transactionId: transactionId, state: savedTransaction }, - 'Got transaction details' + const maxmemoryPolicyConfig = await (redis as Redis).config( + 'GET', + 'maxmemory-policy' ); + logger.debug({ maxmemoryPolicyConfig }, 'Got maxmemory-policy config'); - const transactionDetails = { - transactionId: transactionId, - mspId: savedTransaction.mspId, - transactionState: Buffer.from(savedTransaction.state), - transactionArgs: savedTransaction.args, - timestamp: parseInt(savedTransaction.timestamp), - retries: parseInt(savedTransaction.retries), - }; - return transactionDetails; - } catch (err) { - // TODO just log?! - logger.error( - { err }, - 'Error getting details for transaction ID %s', - transactionId - ); - } -}; - -/* - * Get the oldest transaction details - */ -export const getRetryTransactionDetails = async ( - redis: Redis -): Promise => { - try { - const transactionIds = await (redis as Redis).zrange( - 'index:txn:timestamp', - -1, - -1 - ); - - if (transactionIds.length > 0) { - const transactionId = transactionIds[0]; - - const savedTransaction = await getTransactionDetails( - redis, - transactionId - ); - return savedTransaction; + if ( + maxmemoryPolicyConfig.length == 2 && + 'maxmemory-policy' === maxmemoryPolicyConfig[0] && + 'noeviction' === maxmemoryPolicyConfig[1] + ) { + return true; + } + } finally { + if (redis != undefined) { + redis.disconnect(); } - } catch (err) { - // TODO just log?! - logger.error( - { err }, - 'Error getting details for next transaction to retry' - ); } -}; -/* - * Delete transaction details - */ -export const clearTransactionDetails = async ( - redis: Redis, - transactionId: string -): Promise => { - const key = `txn:${transactionId}`; - logger.debug('Removing transaction details. Key: %s', key); - try { - await redis - .multi() - .del(key) - .zrem('index:txn:timestamp', transactionId) - .exec(); - } catch (err) { - // TODO just log?! - logger.error( - { err }, - 'Error remove details for transaction ID %s', - transactionId - ); - } -}; - -/* - * Increment the number of times the transaction has been retried - - * TODO needs to update the timestamp and index as well - */ -export const incrementRetryCount = async ( - redis: Redis, - transactionId: string -): Promise => { - const key = `txn:${transactionId}`; - logger.debug('Incrementing retries fortransaction Key: %s', key); - try { - await (redis as Redis).hincrby(`txn:${transactionId}`, 'retries', 1); - } catch (err) { - // TODO just log?! - logger.error( - err, - 'Error incrementing retries for transaction ID %s', - transactionId - ); - } + return false; }; diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index e1f360aa..60ceb481 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -2,30 +2,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -import helmet from 'helmet'; -import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import express, { Application, NextFunction, Request, Response } from 'express'; -import pinoMiddleware from 'pino-http'; -import { Contract } from 'fabric-network'; - -import { logger } from './logger'; -import { assetsRouter } from './assets.router'; -import { healthRouter } from './health.router'; -import { transactionsRouter } from './transactions.router'; -import { - getContracts, - getNetwork, - createGateway, - createWallet, - startRetryLoop, - blockEventHandler, -} from './fabric'; -import { redis } from './redis'; -import * as config from './config'; -const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND } = StatusCodes; - -import { authenticateApiKey, fabricAPIKeyStrategy } from './auth'; +import helmet from 'helmet'; +import { getReasonPhrase, StatusCodes } from 'http-status-codes'; import passport from 'passport'; +import pinoMiddleware from 'pino-http'; +import { assetsRouter } from './assets.router'; +import { authenticateApiKey, fabricAPIKeyStrategy } from './auth'; +import { healthRouter } from './health.router'; +import { jobsRouter } from './jobs.router'; +import { logger } from './logger'; +import { transactionsRouter } from './transactions.router'; + +const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND } = StatusCodes; export const createServer = async (): Promise => { const app = express(); @@ -71,42 +60,9 @@ export const createServer = async (): Promise => { app.use(helmet()); } - const wallet = await createWallet(); - - const gatewayOrg1 = await createGateway( - config.connectionProfileOrg1, - config.mspIdOrg1, - wallet - ); - const networkOrg1 = await getNetwork(gatewayOrg1); - const contractsOrg1 = await getContracts(networkOrg1); - app.set(config.mspIdOrg1, contractsOrg1); - - const gatewayOrg2 = await createGateway( - config.connectionProfileOrg2, - config.mspIdOrg2, - wallet - ); - const networkOrg2 = await getNetwork(gatewayOrg2); - const contractsOrg2 = await getContracts(networkOrg2); - app.set(config.mspIdOrg2, contractsOrg2); - - const assetContracts = new Map(); - assetContracts.set(config.mspIdOrg1, contractsOrg1.assetContract); - assetContracts.set(config.mspIdOrg2, contractsOrg2.assetContract); - startRetryLoop(assetContracts, redis); - - app.set('redis', redis); - - logger.debug('Adding block listener to %s network', config.blockListenerOrg); - if (config.blockListenerOrg === config.ORG1) { - await networkOrg1.addBlockListener(blockEventHandler(redis)); - } else { - await networkOrg2.addBlockListener(blockEventHandler(redis)); - } - app.use('/', healthRouter); app.use('/api/assets', authenticateApiKey, assetsRouter); + app.use('/api/jobs', authenticateApiKey, jobsRouter); app.use('/api/transactions', authenticateApiKey, transactionsRouter); // For everything else diff --git a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts index a91c2fc5..4b729951 100644 --- a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts @@ -4,81 +4,44 @@ import express, { Request, Response } from 'express'; import { Contract } from 'fabric-network'; -import { protos } from 'fabric-protos'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; -import { Redis } from 'ioredis'; -import { getTransactionDetails } from './redis'; -import { evatuateTransaction } from './fabric'; +import { getTransactionValidationCode } from './fabric'; import { logger } from './logger'; -import * as config from './config'; import { TransactionNotFoundError } from './errors'; const { INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; export const transactionsRouter = express.Router(); -type Progress = 'ACCEPTED' | 'RETRYING' | 'DONE'; - transactionsRouter.get( '/:transactionId', async (req: Request, res: Response) => { + const mspId = req.user as string; const transactionId = req.params.transactionId; logger.debug('Read request received for transaction ID %s', transactionId); - let foundTransaction = false; - let progress: Progress = 'DONE'; - let validationCode = ''; - - const mspId = req.user as string; - const qscc = req.app.get(mspId).qsccContract as Contract; - const redis = req.app.get('redis') as Redis; - try { - const savedTransaction = await getTransactionDetails( - redis, + const qsccContract = req.app.get(mspId).qsccContract as Contract; + + const validationCode = await getTransactionValidationCode( + qsccContract, transactionId ); - if (savedTransaction?.transactionState) { - foundTransaction = true; - if (savedTransaction.retries > 0) { - progress = 'RETRYING'; - } else { - progress = 'ACCEPTED'; - } - } - } catch (err) { - logger.error( - err, - 'Redis error processing read request for transaction ID %s', - transactionId - ); - - return res.status(INTERNAL_SERVER_ERROR).json({ - status: getReasonPhrase(INTERNAL_SERVER_ERROR), - timestamp: new Date().toISOString(), + return res.status(OK).json({ + transactionId, + validationCode, }); - } - - try { - const data = await evatuateTransaction( - qscc, - 'GetTransactionByID', - config.channelName, - transactionId - ); - - foundTransaction = true; - // TODO is it possible to use the BlockDecoder decodeTransaction - // function in fabric-common? - const processedTransaction = protos.ProcessedTransaction.decode(data); - validationCode = - protos.TxValidationCode[processedTransaction.validationCode]; } catch (err) { - if (!(err instanceof TransactionNotFoundError)) { + if (err instanceof TransactionNotFoundError) { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } else { logger.error( - err, - 'Fabric error processing read request for transaction ID %s', + { err }, + 'Error processing read request for transaction ID %s', transactionId ); @@ -88,19 +51,5 @@ transactionsRouter.get( }); } } - - if (foundTransaction) { - return res.status(OK).json({ - status: getReasonPhrase(OK), - progress: progress, - validationCode: validationCode, - timestamp: new Date().toISOString(), - }); - } else { - return res.status(NOT_FOUND).json({ - status: getReasonPhrase(NOT_FOUND), - timestamp: new Date().toISOString(), - }); - } } ); From b1bc6663b83dbfb1fd8138b696b5552e2836925e Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 3 Dec 2021 12:23:06 +0000 Subject: [PATCH 090/106] Update readme Minor changes for Fabric 2.4 and the main branch of fabric-samples Signed-off-by: James Taylor --- asset-transfer-basic/rest-api-typescript/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/README.md b/asset-transfer-basic/rest-api-typescript/README.md index b5191620..abfed749 100644 --- a/asset-transfer-basic/rest-api-typescript/README.md +++ b/asset-transfer-basic/rest-api-typescript/README.md @@ -6,7 +6,7 @@ The primary aim of this sample is to show how to write a long running client app The REST API is intended to work with the [basic asset transfer example](https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic) -To install the basic asset transfer chaincode on a local Fabric network, follow the [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/release-2.2/test_network.html) tutorial +To install the basic asset transfer chaincode on a local Fabric network, follow the [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/release-2.4/test_network.html) tutorial ## Overview @@ -25,7 +25,7 @@ Alternatively you might prefer to modify the sample to only retry transactions w ## Usage -**Note:** these instructions should work with the release-2.2 branch of `fabric-samples` but later versions require some changes +**Note:** these instructions should work with the main branch of `fabric-samples` To build and start the sample REST server, you'll need to [download and install an LTS version of node](https://nodejs.org/en/download/) From 2d7da062d839c5f1fe77bfbbbd0a8f8504a701ec Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 3 Dec 2021 12:29:13 +0000 Subject: [PATCH 091/106] Update Dockerfile Fabric is on alpine 3.14 so update the sample to match Signed-off-by: James Taylor --- asset-transfer-basic/rest-api-typescript/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/Dockerfile b/asset-transfer-basic/rest-api-typescript/Dockerfile index 073c68f1..d6e87bd0 100644 --- a/asset-transfer-basic/rest-api-typescript/Dockerfile +++ b/asset-transfer-basic/rest-api-typescript/Dockerfile @@ -1,4 +1,4 @@ -FROM node:14-alpine3.12 AS build +FROM node:14-alpine3.14 AS build RUN apk add --no-cache g++ make python3 dumb-init @@ -10,7 +10,7 @@ RUN npm ci RUN npm run build RUN npm prune --production -FROM node:14-alpine3.12 +FROM node:14-alpine3.14 ENV NODE_ENV production WORKDIR /app From 5a32d803c9eda62e8f9e5c01a474c78c4891640e Mon Sep 17 00:00:00 2001 From: James Taylor Date: Fri, 3 Dec 2021 15:35:30 +0000 Subject: [PATCH 092/106] Use user credentials Use User1 certificate and private key for org1 and org2 instead of Admin credentials Signed-off-by: James Taylor --- .../rest-api-typescript/scripts/generateEnv.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index c910651e..ebdcf073 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -8,12 +8,12 @@ ${AS_LOCAL_HOST:=true} : "${TEST_NETWORK_HOME:=../..}" : "${CONNECTION_PROFILE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" -: "${CERTIFICATE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem}" -: "${PRIVATE_KEY_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/priv_sk}" +: "${CERTIFICATE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem}" +: "${PRIVATE_KEY_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk}" : "${CONNECTION_PROFILE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/connection-org2.json}" -: "${CERTIFICATE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/Admin@org2.example.com-cert.pem}" -: "${PRIVATE_KEY_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/priv_sk}" +: "${CERTIFICATE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/signcerts/User1@org2.example.com-cert.pem}" +: "${PRIVATE_KEY_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/keystore/priv_sk}" cat << ENV_END > .env From b0256a57b54263d5eb0c9a6023803655108d92ce Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 6 Dec 2021 10:56:43 +0000 Subject: [PATCH 093/106] Signpost configuration details Signed-off-by: James Taylor --- .../rest-api-typescript/.env.sample | 46 ++++++------------- .../rest-api-typescript/README.md | 2 + .../scripts/generateEnv.sh | 14 ++---- .../rest-api-typescript/src/config.ts | 23 +++++++--- .../rest-api-typescript/src/index.ts | 9 ++++ 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/.env.sample b/asset-transfer-basic/rest-api-typescript/.env.sample index dc052b68..ab5554ad 100644 --- a/asset-transfer-basic/rest-api-typescript/.env.sample +++ b/asset-transfer-basic/rest-api-typescript/.env.sample @@ -1,39 +1,23 @@ -LOG_LEVEL=info +# Sample .env file +# +# These are the minimum configuration variables required to start the sample +# +# See src/config.ts for details and for all the available configuration +# variables +# -PORT=3000 +HLF_CONNECTION_PROFILE_ORG1= -RETRY_DELAY=3000 +HLF_CERTIFICATE_ORG1= -MAX_RETRY_COUNT=5 +HLF_PRIVATE_KEY_ORG1= -AS_LOCAL_HOST=true +HLF_CONNECTION_PROFILE_ORG2= -HLF_CONNECTION_PROFILE_ORG1={"name":"test-network-org1","version":"1.0.0","client":{"organization":"Org1" ... } +HLF_CERTIFICATE_ORG2= -HLF_CERTIFICATE_ORG1="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" +HLF_PRIVATE_KEY_ORG2= -HLF_PRIVATE_KEY_ORG1="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" +ORG1_APIKEY= -HLF_CONNECTION_PROFILE_ORG2={"name":"test-network-org2","version":"1.0.0","client":{"organization":"Org2" ... } - -HLF_CERTIFICATE_ORG2="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" - -HLF_PRIVATE_KEY_ORG2="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n" - -HLF_COMMIT_TIMEOUT=3000 - -HLF_ENDORSE_TIMEOUT=30 - -HLF_QUERY_TIMEOUT=3 - -REDIS_HOST=localhost - -REDIS_PORT=6379 - -#REDIS_USERNAME= - -#REDIS_PASSWORD= - -ORG1_APIKEY=D2F66BFF-D68B-458D-8FA6-285F172D5B03 - -ORG2_APIKEY=92042C1F-8E58-48F9-9EAF-91A98A2B764 +ORG2_APIKEY= diff --git a/asset-transfer-basic/rest-api-typescript/README.md b/asset-transfer-basic/rest-api-typescript/README.md index abfed749..ceb689a9 100644 --- a/asset-transfer-basic/rest-api-typescript/README.md +++ b/asset-transfer-basic/rest-api-typescript/README.md @@ -23,6 +23,8 @@ Alternatively you might prefer to modify the sample to only retry transactions w - CHAINCODE_VERSION_CONFLICT - EXPIRED_CHAINCODE +See [src/index.ts](src/index.ts) for a description of the sample code structure, and [src/config.ts](src/config.ts) for details of configuring the sample using environment variables. + ## Usage **Note:** these instructions should work with the main branch of `fabric-samples` diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index ebdcf073..626f84b9 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -17,14 +17,14 @@ ${AS_LOCAL_HOST:=true} cat << ENV_END > .env +# Generated .env file +# See src/config.ts for details of all the available configuration variables +# + LOG_LEVEL=info PORT=3000 -RETRY_DELAY=3000 - -MAX_RETRY_COUNT=5 - HLF_CERTIFICATE_ORG1="$(cat ${CERTIFICATE_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" HLF_PRIVATE_KEY_ORG1="$(cat ${PRIVATE_KEY_FILE_ORG1} | sed -e 's/$/\\n/' | tr -d '\r\n')" @@ -33,12 +33,6 @@ HLF_CERTIFICATE_ORG2="$(cat ${CERTIFICATE_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d HLF_PRIVATE_KEY_ORG2="$(cat ${PRIVATE_KEY_FILE_ORG2} | sed -e 's/$/\\n/' | tr -d '\r\n')" -HLF_COMMIT_TIMEOUT=3000 - -HLF_ENDORSE_TIMEOUT=30 - -HLF_QUERY_TIMEOUT=3 - REDIS_PORT=6379 ORG1_APIKEY=$(uuidgen) diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index a15c0cec..46933719 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -1,5 +1,16 @@ /* * SPDX-License-Identifier: Apache-2.0 + * + * The sample REST server can be configured using the environment variables + * documented below + * + * In a local development environment, these variables can be loaded from a + * .env file by starting the server with the following command: + * + * npm start:dev + * + * The scripts/generateEnv.sh script can be used to generate a suitable .env + * file for the Fabric Test Network */ import * as env from 'env-var'; @@ -142,8 +153,8 @@ export const chaincodeName = env */ export const commitTimeout = env .get('HLF_COMMIT_TIMEOUT') - .default('3000') - .example('3000') + .default('300') + .example('300') .asIntPositive(); /* @@ -176,7 +187,7 @@ export const connectionProfileOrg1 = env .asJsonObject() as Record; /* - * Certificate for the Org1 identity + * Certificate for an Org1 identity to evaluate and submit transactions */ export const certificateOrg1 = env .get('HLF_CERTIFICATE_ORG1') @@ -185,7 +196,7 @@ export const certificateOrg1 = env .asString(); /* - * Private key for the Org1 identity + * Private key for an Org1 identity to evaluate and submit transactions */ export const privateKeyOrg1 = env .get('HLF_PRIVATE_KEY_ORG1') @@ -205,7 +216,7 @@ export const connectionProfileOrg2 = env .asJsonObject() as Record; /* - * Certificate for the Org2 identity + * Certificate for an Org2 identity to evaluate and submit transactions */ export const certificateOrg2 = env .get('HLF_CERTIFICATE_ORG2') @@ -214,7 +225,7 @@ export const certificateOrg2 = env .asString(); /* - * Private key for the Org2 identity + * Private key for an Org2 identity to evaluate and submit transactions */ export const privateKeyOrg2 = env .get('HLF_PRIVATE_KEY_ORG2') diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 567d3cbc..6b81651c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -1,5 +1,14 @@ /* * SPDX-License-Identifier: Apache-2.0 + * + * This is the main entrypoint for the sample REST server, which is responsible + * for connecting to the Fabric network and setting up a job queue for + * processing submit transactions + * + * You can find details of other aspects of the sample in the following files: + * + * - config.ts + * descriptions of all the available configuration environment variables */ import { Contract } from 'fabric-network'; From 5d92abc52d9a4467f09336fda229df8ede396f68 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 8 Dec 2021 16:58:27 +0000 Subject: [PATCH 094/106] Clarify retry logic Improve the separation between Fabric logic and the job queue implementation details Signed-off-by: James Taylor --- .../rest-api-typescript/README.md | 2 +- .../rest-api-typescript/src/config.spec.ts | 6 +- .../rest-api-typescript/src/config.ts | 6 +- .../rest-api-typescript/src/errors.spec.ts | 116 +++++++++++++- .../rest-api-typescript/src/errors.ts | 141 ++++++++++++------ .../rest-api-typescript/src/fabric.spec.ts | 129 ---------------- .../rest-api-typescript/src/fabric.ts | 125 +--------------- .../rest-api-typescript/src/index.ts | 23 ++- .../rest-api-typescript/src/jobs.router.ts | 3 +- .../rest-api-typescript/src/jobs.spec.ts | 131 +++++++++++++++- .../rest-api-typescript/src/jobs.ts | 125 +++++++++++++++- .../rest-api-typescript/src/redis.ts | 2 +- 12 files changed, 486 insertions(+), 323 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/README.md b/asset-transfer-basic/rest-api-typescript/README.md index ceb689a9..fda1e708 100644 --- a/asset-transfer-basic/rest-api-typescript/README.md +++ b/asset-transfer-basic/rest-api-typescript/README.md @@ -51,7 +51,7 @@ Create a `.env` file to configure the server for the test network (make sure TES TEST_NETWORK_HOME=$HOME/fabric-samples/test-network npm run generateEnv ``` -Start a Redis server +Start a Redis server (Redis is used to store the queue of submit transactions) ```shell npm run start:redis diff --git a/asset-transfer-basic/rest-api-typescript/src/config.spec.ts b/asset-transfer-basic/rest-api-typescript/src/config.spec.ts index f095c1b5..96ffaad5 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.spec.ts @@ -289,9 +289,9 @@ describe('Config values', () => { }); describe('commitTimeout', () => { - it('defaults to "3000"', () => { + it('defaults to "300"', () => { const config = require('./config'); - expect(config.commitTimeout).toBe(3000); + expect(config.commitTimeout).toBe(300); }); it('can be configured using the "HLF_COMMIT_TIMEOUT" environment variable', () => { @@ -305,7 +305,7 @@ describe('Config values', () => { expect(() => { require('./config'); }).toThrow( - 'env-var: "HLF_COMMIT_TIMEOUT" should be a valid integer. An example of a valid value would be: 3000' + 'env-var: "HLF_COMMIT_TIMEOUT" should be a valid integer. An example of a valid value would be: 300' ); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/config.ts b/asset-transfer-basic/rest-api-typescript/src/config.ts index 46933719..87b64719 100644 --- a/asset-transfer-basic/rest-api-typescript/src/config.ts +++ b/asset-transfer-basic/rest-api-typescript/src/config.ts @@ -3,12 +3,12 @@ * * The sample REST server can be configured using the environment variables * documented below - * + * * In a local development environment, these variables can be loaded from a * .env file by starting the server with the following command: - * + * * npm start:dev - * + * * The scripts/generateEnv.sh script can be used to generate a suitable .env * file for the Fabric Test Network */ diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts b/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts index 6ef490f6..90f37a1c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts @@ -2,15 +2,20 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { TimeoutError, TransactionError } from 'fabric-network'; import { AssetExistsError, AssetNotFoundError, TransactionNotFoundError, + getRetryAction, handleError, isDuplicateTransactionError, isErrorLike, + RetryAction, } from './errors'; +import { mock } from 'jest-mock-extended'; + describe('Errors', () => { describe('isErrorLike', () => { it('returns false for null', () => { @@ -53,6 +58,24 @@ describe('Errors', () => { }); describe('isDuplicateTransactionError', () => { + it('returns true for a TransactionError with a transaction code of DUPLICATE_TXID', () => { + const mockDuplicateTransactionError = mock(); + mockDuplicateTransactionError.transactionCode = 'DUPLICATE_TXID'; + + expect(isDuplicateTransactionError(mockDuplicateTransactionError)).toBe( + true + ); + }); + + it('returns false for a TransactionError without a transaction code of MVCC_READ_CONFLICT', () => { + const mockDuplicateTransactionError = mock(); + mockDuplicateTransactionError.transactionCode = 'MVCC_READ_CONFLICT'; + + expect(isDuplicateTransactionError(mockDuplicateTransactionError)).toBe( + false + ); + }); + it('returns true for an error when all endorsement details are duplicate transaction found', () => { const mockDuplicateTransactionError = { errors: [ @@ -155,13 +178,96 @@ describe('Errors', () => { }); }); + describe('getRetryAction', () => { + it('returns RetryAction.None for duplicate transaction errors', () => { + const mockDuplicateTransactionError = { + errors: [ + { + endorsements: [ + { + details: 'duplicate transaction found', + }, + { + details: 'duplicate transaction found', + }, + { + details: 'duplicate transaction found', + }, + ], + }, + ], + }; + + expect(getRetryAction(mockDuplicateTransactionError)).toBe( + RetryAction.None + ); + }); + + it('returns RetryAction.None for a TransactionNotFoundError', () => { + const mockTransactionNotFoundError = new TransactionNotFoundError('Failed to get transaction with id txn, error Entry not found in index', 'txn1'); + + expect(getRetryAction(mockTransactionNotFoundError)).toBe( + RetryAction.None + ); + }); + + it('returns RetryAction.None for an AssetExistsError', () => { + const mockAssetExistsError = new AssetExistsError('The asset MOCK_ASSET already exists', 'txn1'); + + expect(getRetryAction(mockAssetExistsError)).toBe( + RetryAction.None + ); + }); + + it('returns RetryAction.None for an AssetNotFoundError', () => { + const mockAssetNotFoundError = new AssetNotFoundError('the asset MOCK_ASSET does not exist', 'txn1'); + + expect(getRetryAction(mockAssetNotFoundError)).toBe( + RetryAction.None + ); + }); + + it('returns RetryAction.WithExistingTransactionId for a TimeoutError', () => { + const mockTimeoutError = new TimeoutError('MOCK TIMEOUT ERROR'); + + expect(getRetryAction(mockTimeoutError)).toBe( + RetryAction.WithExistingTransactionId + ); + }); + + it('returns RetryAction.WithNewTransactionId for an MVCC_READ_CONFLICT TransactionError', () => { + const mockTransactionError = mock(); + mockTransactionError.transactionCode = 'MVCC_READ_CONFLICT'; + + expect(getRetryAction(mockTransactionError)).toBe( + RetryAction.WithNewTransactionId + ); + }); + + it('returns RetryAction.WithNewTransactionId for an Error', () => { + const mockError = new Error('MOCK ERROR'); + + expect(getRetryAction(mockError)).toBe( + RetryAction.WithNewTransactionId + ); + }); + + it('returns RetryAction.WithNewTransactionId for a string error', () => { + const mockError = 'MOCK ERROR'; + + expect(getRetryAction(mockError)).toBe( + RetryAction.WithNewTransactionId + ); + }); + }); + describe('handleError', () => { it.each([ 'the asset GOCHAINCODE already exists', 'Asset JAVACHAINCODE already exists', 'The asset JSCHAINCODE already exists', ])( - 'returns an AssetExistsError for errors with an asset already exists message: %s', + 'returns a AssetExistsError for errors with an asset already exists message: %s', (msg) => { expect(handleError('txn1', new Error(msg))).toStrictEqual( new AssetExistsError(msg, 'txn1') @@ -174,7 +280,7 @@ describe('Errors', () => { 'Asset JAVACHAINCODE does not exist', 'The asset JSCHAINCODE does not exist', ])( - 'returns an AssetNotFoundError for errors with an asset does not exist message: %s', + 'returns a AssetNotFoundError for errors with an asset does not exist message: %s', (msg) => { expect(handleError('txn1', new Error(msg))).toStrictEqual( new AssetNotFoundError(msg, 'txn1') @@ -200,10 +306,8 @@ describe('Errors', () => { ); }); - it('returns a new Error object for errors of other types', () => { - expect(handleError('txn1', 42)).toStrictEqual( - new Error('Unhandled error: 42') - ); + it('returns the original error for errors of other types', () => { + expect(handleError('txn1', 42)).toEqual(42); }); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.ts b/asset-transfer-basic/rest-api-typescript/src/errors.ts index 89eaaa6b..66272e87 100644 --- a/asset-transfer-basic/rest-api-typescript/src/errors.ts +++ b/asset-transfer-basic/rest-api-typescript/src/errors.ts @@ -1,9 +1,18 @@ /* * SPDX-License-Identifier: Apache-2.0 + * + * This file contains all the error handling for Fabric transactions, including + * whether a transaction should be retried. */ +import { TimeoutError, TransactionError } from 'fabric-network'; import { logger } from './logger'; +/* + * Base type for errors from the smart contract. + * + * These errors will not be retried. + */ export class ContractError extends Error { transactionId: string; @@ -16,18 +25,23 @@ export class ContractError extends Error { } } +/* + * Represents the error which occurs when the transaction being submitted or + * evaluated is not implemented in a smart contract. + */ export class TransactionNotFoundError extends ContractError { - transactionId: string; - constructor(message: string, transactionId: string) { super(message, transactionId); Object.setPrototypeOf(this, TransactionNotFoundError.prototype); this.name = 'TransactionNotFoundError'; - this.transactionId = transactionId; } } +/* + * Represents the error which occurs in the basic asset transfer smart contract + * implementation when an asset already exists. + */ export class AssetExistsError extends ContractError { constructor(message: string, transactionId: string) { super(message, transactionId); @@ -37,6 +51,10 @@ export class AssetExistsError extends ContractError { } } +/* + * Represents the error which occurs in the basic asset transfer smart contract + * implementation when an asset does not exist. + */ export class AssetNotFoundError extends ContractError { constructor(message: string, transactionId: string) { super(message, transactionId); @@ -46,18 +64,53 @@ export class AssetNotFoundError extends ContractError { } } -export class JobNotFoundError extends Error { - jobId: string; - - constructor(message: string, jobId: string) { - super(message); - Object.setPrototypeOf(this, JobNotFoundError.prototype); - - this.name = 'JobNotFoundError'; - this.jobId = jobId; - } +/* + * Enumeration of possible retry actions. + * + * WithExistingTransactionId - transactions should be retried using the same + * transaction ID to protect against duplicate transactions being committed if + * a timeout error occurs + * + * WithNewTransactionId - transactions which could not be committed due to + * other errors require a new transaction ID when retrying + * + * None - transactions that failed due to a duplicate transaction error, or + * errors from the smart contract, should not be retried + */ +export enum RetryAction { + WithExistingTransactionId, + WithNewTransactionId, + None, } +/* + * Get the required transaction retry action for an error. + * + * For this sample transactions are considered retriable if they fail with any + * error, *except* for duplicate transaction errors, or errors from the smart + * contract. + * + * You might decide to retry transactions which fail with specific errors + * instead, for example: + * MVCC_READ_CONFLICT + * PHANTOM_READ_CONFLICT + * ENDORSEMENT_POLICY_FAILURE + * CHAINCODE_VERSION_CONFLICT + * EXPIRED_CHAINCODE + */ +export const getRetryAction = (err: unknown): RetryAction => { + if (isDuplicateTransactionError(err) || err instanceof ContractError) { + return RetryAction.None; + } else if (err instanceof TimeoutError) { + return RetryAction.WithExistingTransactionId; + } + + return RetryAction.WithNewTransactionId; +}; + +/* + * Type guard to make catching unknown errors easier + */ export const isErrorLike = (err: unknown): err is Error => { return ( err != undefined && @@ -72,23 +125,32 @@ export const isErrorLike = (err: unknown): err is Error => { /* * Checks whether an error was caused by a duplicate transaction. * - * Checking error strings like this is not ideal, unfortunately it appears to - * be the only option. In this case it would be better to check for the - * DUPLICATE_TXID TxValidationCode somehow but that does not seem to be - * possible. + * This is ...painful. */ export const isDuplicateTransactionError = (err: unknown): boolean => { + logger.debug({ err }, 'Checking for duplicate transaction error'); + if (err === undefined || err === null) return false; - const endorsementError = err as { - errors: { endorsements: { details: string }[] }[]; - }; + let isDuplicate; + if (typeof (err as TransactionError).transactionCode === 'string') { + // Checking whether a commit failure is caused by a duplicate transaction + // is straightforward because the transaction code should be available + isDuplicate = + (err as TransactionError).transactionCode === 'DUPLICATE_TXID'; + } else { + // Checking whether an endorsement failure is caused by a duplicate + // transaction is only possible by processing error strings, which is not ideal. + const endorsementError = err as { + errors: { endorsements: { details: string }[] }[]; + }; - const isDuplicate = endorsementError?.errors?.some((err) => - err?.endorsements?.some((endorsement) => - endorsement?.details?.startsWith('duplicate transaction found') - ) - ); + isDuplicate = endorsementError?.errors?.some((err) => + err?.endorsements?.some((endorsement) => + endorsement?.details?.startsWith('duplicate transaction found') + ) + ); + } return isDuplicate === true; }; @@ -167,27 +229,18 @@ const matchTransactionDoesNotExistMessage = ( return null; }; -export const isContractError = (err: unknown): boolean => { - if ( - err instanceof AssetExistsError || - err instanceof AssetNotFoundError || - err instanceof TransactionNotFoundError - ) { - return true; - } - - return false; -}; - /* * Handles errors from evaluating and submitting transactions. * - * As with duplicate transaction errors, checking error strings like this is - * not ideal. Unfortunately the chaincode samples do not use error codes so - * again it's the only option. The error message text is not even the same for - * the Go, Java, and Javascript implementations of the chaincode! + * Smart contract errors from the the basic asset transfer samples do not use + * error codes so matching strings is the only option, which is not ideal. + * Note: the error message text is not the same for the Go, Java, and + * Javascript implementations of the chaincode! */ -export const handleError = (transactionId: string, err: unknown): Error => { +export const handleError = ( + transactionId: string, + err: unknown +): Error | unknown => { logger.debug({ transactionId: transactionId, err }, 'Processing error'); if (isErrorLike(err)) { @@ -210,9 +263,7 @@ export const handleError = (transactionId: string, err: unknown): Error => { transactionId ); } - - return err; } - return new Error(`Unhandled error: ${err}`); + return err; }; diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts index 34e6f2f0..b7ba2805 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.spec.ts @@ -11,7 +11,6 @@ import { submitTransaction, getBlockHeight, getTransactionValidationCode, - processSubmitTransactionJob, } from './fabric'; import * as config from './config'; @@ -34,7 +33,6 @@ import * as fabricProtos from 'fabric-protos'; import { MockProxy, mock } from 'jest-mock-extended'; import Long from 'long'; -import { Job } from 'bullmq'; jest.mock('./config'); jest.mock('fabric-network', () => { @@ -117,133 +115,6 @@ describe('Fabric', () => { }); }); - describe('processSubmitTransactionJob', () => { - const mockContracts = new Map(); - const mockPayload = Buffer.from('MOCK PAYLOAD'); - const mockSavedState = Buffer.from('MOCK SAVED STATE'); - let mockTransaction: MockProxy; - let mockContract: MockProxy; - let mockJob: MockProxy; - - beforeEach(() => { - mockTransaction = mock(); - mockTransaction.getTransactionId.mockReturnValue('mockTransactionId'); - - mockContract = mock(); - mockContract.createTransaction - .calledWith('txn') - .mockReturnValue(mockTransaction); - mockContract.deserializeTransaction - .calledWith(mockSavedState) - .mockReturnValue(mockTransaction); - mockContracts.set('mockMspid', mockContract); - - mockJob = mock(); - }); - - it('gets job result with no error or payload if no contract is available for the required mspid', async () => { - mockJob.data = { - mspid: 'missingMspid', - }; - - const jobResult = await processSubmitTransactionJob( - mockContracts, - mockJob - ); - - expect(jobResult).toStrictEqual({ - transactionError: undefined, - transactionPayload: undefined, - }); - }); - - it('gets a job result containing a payload if the transaction was successful first time', async () => { - mockJob.data = { - mspid: 'mockMspid', - transactionName: 'txn', - transactionArgs: ['arg1', 'arg2'], - }; - mockTransaction.submit - .calledWith('arg1', 'arg2') - .mockResolvedValue(mockPayload); - - const jobResult = await processSubmitTransactionJob( - mockContracts, - mockJob - ); - - expect(jobResult).toStrictEqual({ - transactionError: undefined, - transactionPayload: Buffer.from('MOCK PAYLOAD'), - }); - }); - - it('gets a job result containing a payload if the transaction was successfully rerun using saved transaction state', async () => { - mockJob.data = { - mspid: 'mockMspid', - transactionName: 'txn', - transactionArgs: ['arg1', 'arg2'], - transactionState: mockSavedState, - }; - mockTransaction.submit - .calledWith('arg1', 'arg2') - .mockResolvedValue(mockPayload); - - const jobResult = await processSubmitTransactionJob( - mockContracts, - mockJob - ); - - expect(jobResult).toStrictEqual({ - transactionError: undefined, - transactionPayload: Buffer.from('MOCK PAYLOAD'), - }); - }); - - it('gets a job result containing an error message if the transaction fails but cannot be retried', async () => { - mockJob.data = { - mspid: 'mockMspid', - transactionName: 'txn', - transactionArgs: ['arg1', 'arg2'], - transactionState: mockSavedState, - }; - mockTransaction.submit - .calledWith('arg1', 'arg2') - .mockRejectedValue( - new Error( - 'Failed to get transaction with id txn, error Entry not found in index' - ) - ); - - const jobResult = await processSubmitTransactionJob( - mockContracts, - mockJob - ); - - expect(jobResult).toStrictEqual({ - transactionError: - 'TransactionNotFoundError: Failed to get transaction with id txn, error Entry not found in index', - transactionPayload: undefined, - }); - }); - - it('throws an error if the transaction fails but can be retried', async () => { - mockJob.data = { - mspid: 'mockMspid', - transactionName: 'txn', - transactionArgs: ['arg1', 'arg2'], - transactionState: mockSavedState, - }; - mockTransaction.submit - .calledWith('arg1', 'arg2') - .mockRejectedValue(new Error('MOCK ERROR')); - - await expect(async () => { - await processSubmitTransactionJob(mockContracts, mockJob); - }).rejects.toThrow('MOCK ERROR'); - }); - }); - describe('evatuateTransaction', () => { const mockPayload = Buffer.from('MOCK PAYLOAD'); let mockTransaction: MockProxy; diff --git a/asset-transfer-basic/rest-api-typescript/src/fabric.ts b/asset-transfer-basic/rest-api-typescript/src/fabric.ts index 70a3a6f2..1a9f8b6e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/fabric.ts +++ b/asset-transfer-basic/rest-api-typescript/src/fabric.ts @@ -10,20 +10,13 @@ import { GatewayOptions, Wallets, Network, - TimeoutError, Transaction, Wallet, } from 'fabric-network'; import * as config from './config'; import { logger } from './logger'; -import { - handleError, - isContractError, - isDuplicateTransactionError, -} from './errors'; +import { handleError } from './errors'; import * as protos from 'fabric-protos'; -import { Job } from 'bullmq'; -import { JobData, JobResult, updateJobData } from './jobs'; /* * Creates an in memory wallet to hold credentials for an Org1 and Org2 user @@ -120,122 +113,6 @@ export const getContracts = async ( return { assetContract, qsccContract }; }; -/* - * Process a submit transaction request from the job queue - * - * For this sample transactions are retried if they fail with any error, - * except for errors from the smart contract, or duplicate transaction - * errors - * - * You might decide to retry transactions which fail with specific errors - * instead, for example: - * MVCC_READ_CONFLICT - * PHANTOM_READ_CONFLICT - * ENDORSEMENT_POLICY_FAILURE - * CHAINCODE_VERSION_CONFLICT - * EXPIRED_CHAINCODE - */ -export const processSubmitTransactionJob = async ( - contracts: Map, - job: Job -): Promise => { - logger.debug({ jobId: job.id, jobName: job.name }, 'Processing job'); - - const contract = contracts.get(job.data.mspid); - if (contract === undefined) { - logger.error( - { jobId: job.id, jobName: job.name }, - 'Contract not found for MSP ID %s', - job.data.mspid - ); - - // Retrying will not work, so give up with an unsuccessful result - return { - transactionError: undefined, - transactionPayload: undefined, - }; - } - - let transaction: Transaction; - if (job.data.transactionState) { - const savedState = job.data.transactionState; - logger.debug( - { - jobId: job.id, - jobName: job.name, - savedState, - }, - 'Using previously saved transaction state' - ); - - transaction = contract.deserializeTransaction(savedState); - } else { - logger.debug( - { - jobId: job.id, - jobName: job.name, - }, - 'Using new transaction' - ); - - transaction = contract.createTransaction(job.data.transactionName); - await updateJobData(job, transaction); - } - - try { - logger.debug( - { - jobId: job.id, - jobName: job.name, - transactionId: transaction.getTransactionId(), - }, - 'Submitting transaction' - ); - const args = job.data.transactionArgs; - const payload = await submitTransaction(transaction, ...args); - - return { - transactionError: undefined, - transactionPayload: payload, - }; - } catch (err) { - if ( - err instanceof Error && - (isContractError(err) || isDuplicateTransactionError(err)) - ) { - logger.error( - { jobId: job.id, jobName: job.name, err }, - 'Fatal transaction error occurred' - ); - - // Return a job result to stop retrying - return { - transactionError: err.toString(), - transactionPayload: undefined, - }; - } else { - logger.warn( - { jobId: job.id, jobName: job.name, err }, - 'Retryable transaction error occurred' - ); - - // The original transaction may eventually get committed in the case of - // a timeout error, so keep the same transaction ID to protect against - // unintended duplicate transactions - if (!(err instanceof TimeoutError)) { - logger.debug( - { jobId: job.id, jobName: job.name }, - 'Clearing saved transaction state' - ); - await updateJobData(job, undefined); - } - - // Rethrow the error to keep retrying - throw err; - } - } -}; - /* * Evaluate a transaction and handle any errors */ diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 6b81651c..1e222713 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -4,11 +4,32 @@ * This is the main entrypoint for the sample REST server, which is responsible * for connecting to the Fabric network and setting up a job queue for * processing submit transactions + * + * You can find more details related to the Fabric aspects of the sample in the + * following files: + * + * - errors.ts + * Fabric transaction error handling and retry logic + * - fabric.ts + * all the sample code which interacts with the Fabric SDK * - * You can find details of other aspects of the sample in the following files: + * The remaining files are related to the REST server aspects of the sample, + * rather than Fabric itself: * + * - *.router.ts + * details of the REST endpoints provided by the sample + * - auth.ts + * basic API key authentication strategy used for the sample * - config.ts * descriptions of all the available configuration environment variables + * - jobs.ts + * job queue implementation details + * - logger.ts + * logging implementation details + * - redis.ts + * redis implementation details + * - server.ts + * express server implementation details */ import { Contract } from 'fabric-network'; diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts index 097d19a7..77dc5fe9 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts @@ -5,8 +5,7 @@ import { Queue } from 'bullmq'; import express, { Request, Response } from 'express'; import { getReasonPhrase, StatusCodes } from 'http-status-codes'; -import { JobNotFoundError } from './errors'; -import { getJobSummary } from './jobs'; +import { getJobSummary, JobNotFoundError } from './jobs'; import { logger } from './logger'; const { INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts index 05fe6af0..43ba4d6d 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts @@ -3,9 +3,9 @@ */ import { Job, Queue } from 'bullmq'; -import { getJobCounts, getJobSummary } from './jobs'; +import { getJobCounts, getJobSummary, processSubmitTransactionJob, JobNotFoundError } from './jobs'; +import { Contract, Transaction } from 'fabric-network'; import { mock, MockProxy } from 'jest-mock-extended'; -import { JobNotFoundError } from './errors'; describe('initJobQueue', () => { it.todo('write tests'); @@ -152,4 +152,131 @@ describe('getJobCounts', () => { waiting: 5, }); }); + + describe('processSubmitTransactionJob', () => { + const mockContracts = new Map(); + const mockPayload = Buffer.from('MOCK PAYLOAD'); + const mockSavedState = Buffer.from('MOCK SAVED STATE'); + let mockTransaction: MockProxy; + let mockContract: MockProxy; + let mockJob: MockProxy; + + beforeEach(() => { + mockTransaction = mock(); + mockTransaction.getTransactionId.mockReturnValue('mockTransactionId'); + + mockContract = mock(); + mockContract.createTransaction + .calledWith('txn') + .mockReturnValue(mockTransaction); + mockContract.deserializeTransaction + .calledWith(mockSavedState) + .mockReturnValue(mockTransaction); + mockContracts.set('mockMspid', mockContract); + + mockJob = mock(); + }); + + it('gets job result with no error or payload if no contract is available for the required mspid', async () => { + mockJob.data = { + mspid: 'missingMspid', + }; + + const jobResult = await processSubmitTransactionJob( + mockContracts, + mockJob + ); + + expect(jobResult).toStrictEqual({ + transactionError: undefined, + transactionPayload: undefined, + }); + }); + + it('gets a job result containing a payload if the transaction was successful first time', async () => { + mockJob.data = { + mspid: 'mockMspid', + transactionName: 'txn', + transactionArgs: ['arg1', 'arg2'], + }; + mockTransaction.submit + .calledWith('arg1', 'arg2') + .mockResolvedValue(mockPayload); + + const jobResult = await processSubmitTransactionJob( + mockContracts, + mockJob + ); + + expect(jobResult).toStrictEqual({ + transactionError: undefined, + transactionPayload: Buffer.from('MOCK PAYLOAD'), + }); + }); + + it('gets a job result containing a payload if the transaction was successfully rerun using saved transaction state', async () => { + mockJob.data = { + mspid: 'mockMspid', + transactionName: 'txn', + transactionArgs: ['arg1', 'arg2'], + transactionState: mockSavedState, + }; + mockTransaction.submit + .calledWith('arg1', 'arg2') + .mockResolvedValue(mockPayload); + + const jobResult = await processSubmitTransactionJob( + mockContracts, + mockJob + ); + + expect(jobResult).toStrictEqual({ + transactionError: undefined, + transactionPayload: Buffer.from('MOCK PAYLOAD'), + }); + }); + + it('gets a job result containing an error message if the transaction fails but cannot be retried', async () => { + mockJob.data = { + mspid: 'mockMspid', + transactionName: 'txn', + transactionArgs: ['arg1', 'arg2'], + transactionState: mockSavedState, + }; + mockTransaction.submit + .calledWith('arg1', 'arg2') + .mockRejectedValue( + new Error( + 'Failed to get transaction with id txn, error Entry not found in index' + ) + ); + + const jobResult = await processSubmitTransactionJob( + mockContracts, + mockJob + ); + + expect(jobResult).toStrictEqual({ + transactionError: + 'TransactionNotFoundError: Failed to get transaction with id txn, error Entry not found in index', + transactionPayload: undefined, + }); + }); + + it('throws an error if the transaction fails but can be retried', async () => { + mockJob.data = { + mspid: 'mockMspid', + transactionName: 'txn', + transactionArgs: ['arg1', 'arg2'], + transactionState: mockSavedState, + }; + mockTransaction.submit + .calledWith('arg1', 'arg2') + .mockRejectedValue(new Error('MOCK ERROR')); + + await expect(async () => { + await processSubmitTransactionJob(mockContracts, mockJob); + }).rejects.toThrow('MOCK ERROR'); + }); + }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.ts index da397a2d..2b4f2399 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.ts @@ -3,17 +3,13 @@ * * This sample uses BullMQ jobs to process submit transactions, which includes * retry support for failing jobs - * - * Important: BullMQ requires the following setting in redis - * maxmemory-policy=noeviction - * For details, see: https://docs.bullmq.io/guide/connections */ import { ConnectionOptions, Job, Queue, QueueScheduler, Worker } from 'bullmq'; import { Contract, Transaction } from 'fabric-network'; import * as config from './config'; -import { JobNotFoundError } from './errors'; -import { processSubmitTransactionJob } from './fabric'; +import { getRetryAction, RetryAction } from './errors'; +import { submitTransaction } from './fabric'; import { logger } from './logger'; export type JobData = { @@ -37,6 +33,18 @@ export type JobSummary = { transactionError?: string; }; +export class JobNotFoundError extends Error { + jobId: string; + + constructor(message: string, jobId: string) { + super(message); + Object.setPrototypeOf(this, JobNotFoundError.prototype); + + this.name = 'JobNotFoundError'; + this.jobId = jobId; + } +} + const connection: ConnectionOptions = { port: config.redisPort, host: config.redisHost, @@ -214,3 +222,108 @@ export const getJobCounts = async ( return jobCounts; }; + +/* + * Process a submit transaction request from the job queue + * + * The job will be retried if this function throws an error + */ +export const processSubmitTransactionJob = async ( + contracts: Map, + job: Job +): Promise => { + logger.debug({ jobId: job.id, jobName: job.name }, 'Processing job'); + + const contract = contracts.get(job.data.mspid); + if (contract === undefined) { + logger.error( + { jobId: job.id, jobName: job.name }, + 'Contract not found for MSP ID %s', + job.data.mspid + ); + + // Retrying will never work without a contract, so give up with an + // empty job result + return { + transactionError: undefined, + transactionPayload: undefined, + }; + } + + const args = job.data.transactionArgs; + let transaction: Transaction; + + if (job.data.transactionState) { + const savedState = job.data.transactionState; + logger.debug( + { + jobId: job.id, + jobName: job.name, + savedState, + }, + 'Reusing previously saved transaction state' + ); + + transaction = contract.deserializeTransaction(savedState); + } else { + logger.debug( + { + jobId: job.id, + jobName: job.name, + }, + 'Using new transaction' + ); + + transaction = contract.createTransaction(job.data.transactionName); + await updateJobData(job, transaction); + } + + logger.debug( + { + jobId: job.id, + jobName: job.name, + transactionId: transaction.getTransactionId(), + }, + 'Submitting transaction' + ); + + try { + const payload = await submitTransaction(transaction, ...args); + + return { + transactionError: undefined, + transactionPayload: payload, + }; + } catch (err) { + const retryAction = getRetryAction(err); + + if (retryAction === RetryAction.None) { + logger.error( + { jobId: job.id, jobName: job.name, err }, + 'Fatal transaction error occurred' + ); + + // Not retriable so return a job result with the error details + return { + transactionError: `${err}`, + transactionPayload: undefined, + }; + } + + logger.warn( + { jobId: job.id, jobName: job.name, err }, + 'Retryable transaction error occurred' + ); + + if (retryAction === RetryAction.WithNewTransactionId) { + logger.debug( + { jobId: job.id, jobName: job.name }, + 'Clearing saved transaction state' + ); + await updateJobData(job, undefined); + } + + // Rethrow the error to keep retrying + throw err; + } +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/redis.ts b/asset-transfer-basic/rest-api-typescript/src/redis.ts index bb4246da..35865545 100644 --- a/asset-transfer-basic/rest-api-typescript/src/redis.ts +++ b/asset-transfer-basic/rest-api-typescript/src/redis.ts @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: Apache-2.0 * - * TBC + * This sample uses the BullMQ queue system, which is built on top of Redis */ import IORedis, { Redis, RedisOptions } from 'ioredis'; From 66199000caf600fdd3c6110b89a42bb68c49cc57 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 13 Dec 2021 12:11:59 +0000 Subject: [PATCH 095/106] Fix lint errors Signed-off-by: James Taylor --- .../rest-api-typescript/src/errors.spec.ts | 31 ++++++++++--------- .../rest-api-typescript/src/index.ts | 4 +-- .../rest-api-typescript/src/jobs.spec.ts | 7 ++++- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts b/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts index 90f37a1c..ddf4c9f0 100644 --- a/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/errors.spec.ts @@ -204,7 +204,10 @@ describe('Errors', () => { }); it('returns RetryAction.None for a TransactionNotFoundError', () => { - const mockTransactionNotFoundError = new TransactionNotFoundError('Failed to get transaction with id txn, error Entry not found in index', 'txn1'); + const mockTransactionNotFoundError = new TransactionNotFoundError( + 'Failed to get transaction with id txn, error Entry not found in index', + 'txn1' + ); expect(getRetryAction(mockTransactionNotFoundError)).toBe( RetryAction.None @@ -212,19 +215,21 @@ describe('Errors', () => { }); it('returns RetryAction.None for an AssetExistsError', () => { - const mockAssetExistsError = new AssetExistsError('The asset MOCK_ASSET already exists', 'txn1'); - - expect(getRetryAction(mockAssetExistsError)).toBe( - RetryAction.None + const mockAssetExistsError = new AssetExistsError( + 'The asset MOCK_ASSET already exists', + 'txn1' ); + + expect(getRetryAction(mockAssetExistsError)).toBe(RetryAction.None); }); it('returns RetryAction.None for an AssetNotFoundError', () => { - const mockAssetNotFoundError = new AssetNotFoundError('the asset MOCK_ASSET does not exist', 'txn1'); - - expect(getRetryAction(mockAssetNotFoundError)).toBe( - RetryAction.None + const mockAssetNotFoundError = new AssetNotFoundError( + 'the asset MOCK_ASSET does not exist', + 'txn1' ); + + expect(getRetryAction(mockAssetNotFoundError)).toBe(RetryAction.None); }); it('returns RetryAction.WithExistingTransactionId for a TimeoutError', () => { @@ -247,17 +252,13 @@ describe('Errors', () => { it('returns RetryAction.WithNewTransactionId for an Error', () => { const mockError = new Error('MOCK ERROR'); - expect(getRetryAction(mockError)).toBe( - RetryAction.WithNewTransactionId - ); + expect(getRetryAction(mockError)).toBe(RetryAction.WithNewTransactionId); }); it('returns RetryAction.WithNewTransactionId for a string error', () => { const mockError = 'MOCK ERROR'; - expect(getRetryAction(mockError)).toBe( - RetryAction.WithNewTransactionId - ); + expect(getRetryAction(mockError)).toBe(RetryAction.WithNewTransactionId); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index 1e222713..e033db4c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -12,10 +12,10 @@ * Fabric transaction error handling and retry logic * - fabric.ts * all the sample code which interacts with the Fabric SDK - * + * * The remaining files are related to the REST server aspects of the sample, * rather than Fabric itself: - * + * * - *.router.ts * details of the REST endpoints provided by the sample * - auth.ts diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts index 43ba4d6d..e0a60fa7 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts @@ -3,7 +3,12 @@ */ import { Job, Queue } from 'bullmq'; -import { getJobCounts, getJobSummary, processSubmitTransactionJob, JobNotFoundError } from './jobs'; +import { + getJobCounts, + getJobSummary, + processSubmitTransactionJob, + JobNotFoundError, +} from './jobs'; import { Contract, Transaction } from 'fabric-network'; import { mock, MockProxy } from 'jest-mock-extended'; From 711f1f560b28028a3e8f11a05d1c481691f559e4 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 13 Dec 2021 17:06:31 +0000 Subject: [PATCH 096/106] Use app.locals to store contracts and jobq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “The app.locals object has properties that are local variables within the application.” …which looks like a better option than app.get and app.set for app settings. Also passes app to the initJobQueueWorker function for consistency. Signed-off-by: James Taylor --- .../src/__tests__/api.test.ts | 22 +++++++++--------- .../rest-api-typescript/src/assets.router.ts | 14 +++++------ .../rest-api-typescript/src/health.router.ts | 6 ++--- .../rest-api-typescript/src/index.ts | 23 +++++++++---------- .../rest-api-typescript/src/jobs.router.ts | 2 +- .../rest-api-typescript/src/jobs.spec.ts | 15 ++++++++---- .../rest-api-typescript/src/jobs.ts | 11 ++++----- .../src/transactions.router.ts | 2 +- 8 files changed, 49 insertions(+), 46 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts index 06d29dba..b1097bc0 100644 --- a/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts +++ b/asset-transfer-basic/rest-api-typescript/src/__tests__/api.test.ts @@ -48,7 +48,7 @@ describe('Asset Transfer Besic REST API', () => { mockJob.id = '1'; mockJobQueue = mock(); mockJobQueue.add.mockResolvedValue(mockJob); - app.set('jobq', mockJobQueue); + app.locals.jobq = mockJobQueue; }); describe('/ready', () => { @@ -81,17 +81,17 @@ describe('Asset Transfer Besic REST API', () => { mockOrg1QsccContract.evaluateTransaction .calledWith('GetChainInfo') .mockResolvedValue(mockBlockchainInfoBuffer); - app.set(config.mspIdOrg1, { + app.locals[config.mspIdOrg1] = { qsccContract: mockOrg1QsccContract, - }); + }; const mockOrg2QsccContract = mock(); mockOrg2QsccContract.evaluateTransaction .calledWith('GetChainInfo') .mockResolvedValue(mockBlockchainInfoBuffer); - app.set(config.mspIdOrg2, { + app.locals[config.mspIdOrg2] = { qsccContract: mockOrg2QsccContract, - }); + }; const response = await request(app).get('/live'); expect(response.statusCode).toEqual(200); @@ -115,9 +115,9 @@ describe('Asset Transfer Besic REST API', () => { mockBasicContract.createTransaction .calledWith('GetAllAssets') .mockReturnValue(mockGetAllAssetsTransaction); - app.set(config.mspIdOrg1, { + app.locals[config.mspIdOrg1] = { assetContract: mockBasicContract, - }); + }; }); it('GET should respond with 401 unauthorized json when an invalid API key is specified', async () => { @@ -276,9 +276,9 @@ describe('Asset Transfer Besic REST API', () => { .calledWith('ReadAsset') .mockReturnValue(mockReadAssetTransaction); - app.set(config.mspIdOrg1, { + app.locals[config.mspIdOrg1] = { assetContract: mockBasicContract, - }); + }; }); it('OPTIONS should respond with 401 unauthorized json when an invalid API key is specified', async () => { @@ -663,9 +663,9 @@ describe('Asset Transfer Besic REST API', () => { mockQsccContract.createTransaction .calledWith('GetTransactionByID') .mockReturnValue(mockGetTransactionByIDTransaction); - app.set(config.mspIdOrg1, { + app.locals[config.mspIdOrg1] = { qsccContract: mockQsccContract, - }); + }; }); it('GET should respond with 401 unauthorized json when an invalid API key is specified', async () => { diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 5d6c96f5..0af215d1 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -38,7 +38,7 @@ assetsRouter.get('/', async (req: Request, res: Response) => { try { const mspId = req.user as string; - const contract = req.app.get(mspId).assetContract as Contract; + const contract = req.app.locals[mspId]?.assetContract as Contract; const data = await evatuateTransaction(contract, 'GetAllAssets'); let assets = []; @@ -82,7 +82,7 @@ assetsRouter.post( const assetId = req.body.id; try { - const submitQueue = req.app.get('jobq') as Queue; + const submitQueue = req.app.locals.jobq as Queue; const jobId = await addSubmitTransactionJob( submitQueue, mspId, @@ -120,7 +120,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => { try { const mspId = req.user as string; - const contract = req.app.get(mspId).assetContract as Contract; + const contract = req.app.locals[mspId]?.assetContract as Contract; const data = await evatuateTransaction(contract, 'AssetExists', assetId); const exists = data.toString() === 'true'; @@ -160,7 +160,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { try { const mspId = req.user as string; - const contract = req.app.get(mspId).assetContract as Contract; + const contract = req.app.locals[mspId]?.assetContract as Contract; const data = await evatuateTransaction(contract, 'ReadAsset', assetId); const asset = JSON.parse(data.toString()); @@ -222,7 +222,7 @@ assetsRouter.put( const assetId = req.params.assetId; try { - const submitQueue = req.app.get('jobq') as Queue; + const submitQueue = req.app.locals.jobq as Queue; const jobId = await addSubmitTransactionJob( submitQueue, mspId, @@ -284,7 +284,7 @@ assetsRouter.patch( const newOwner = req.body[0].value; try { - const submitQueue = req.app.get('jobq') as Queue; + const submitQueue = req.app.locals.jobq as Queue; const jobId = await addSubmitTransactionJob( submitQueue, mspId, @@ -320,7 +320,7 @@ assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { const assetId = req.params.assetId; try { - const submitQueue = req.app.get('jobq') as Queue; + const submitQueue = req.app.locals.jobq as Queue; const jobId = await addSubmitTransactionJob( submitQueue, mspId, diff --git a/asset-transfer-basic/rest-api-typescript/src/health.router.ts b/asset-transfer-basic/rest-api-typescript/src/health.router.ts index 463ee0e4..e0e32588 100644 --- a/asset-transfer-basic/rest-api-typescript/src/health.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/health.router.ts @@ -30,9 +30,9 @@ healthRouter.get('/live', async (req: Request, res: Response) => { logger.debug(req.body, 'Liveness request received'); try { - const submitQueue = req.app.get('jobq') as Queue; - const qsccOrg1 = req.app.get(config.mspIdOrg1).qsccContract as Contract; - const qsccOrg2 = req.app.get(config.mspIdOrg2).qsccContract as Contract; + const submitQueue = req.app.locals.jobq as Queue; + const qsccOrg1 = req.app.locals[config.mspIdOrg1]?.qsccContract as Contract; + const qsccOrg2 = req.app.locals[config.mspIdOrg2]?.qsccContract as Contract; await Promise.all([ getBlockHeight(qsccOrg1), diff --git a/asset-transfer-basic/rest-api-typescript/src/index.ts b/asset-transfer-basic/rest-api-typescript/src/index.ts index e033db4c..c9a08574 100644 --- a/asset-transfer-basic/rest-api-typescript/src/index.ts +++ b/asset-transfer-basic/rest-api-typescript/src/index.ts @@ -32,7 +32,6 @@ * express server implementation details */ -import { Contract } from 'fabric-network'; import * as config from './config'; import { createGateway, @@ -62,7 +61,10 @@ async function main() { ); } - logger.info('Connecting to Fabric network'); + logger.info('Creating REST server'); + const app = await createServer(); + + logger.info('Connecting to Fabric network with org1 mspid'); const wallet = await createWallet(); const gatewayOrg1 = await createGateway( @@ -73,6 +75,9 @@ async function main() { const networkOrg1 = await getNetwork(gatewayOrg1); const contractsOrg1 = await getContracts(networkOrg1); + app.locals[config.mspIdOrg1] = contractsOrg1; + + logger.info('Connecting to Fabric network with org2 mspid'); const gatewayOrg2 = await createGateway( config.connectionProfileOrg2, config.mspIdOrg2, @@ -81,24 +86,18 @@ async function main() { const networkOrg2 = await getNetwork(gatewayOrg2); const contractsOrg2 = await getContracts(networkOrg2); - const assetContracts = new Map(); - assetContracts.set(config.mspIdOrg1, contractsOrg1.assetContract); - assetContracts.set(config.mspIdOrg2, contractsOrg2.assetContract); + app.locals[config.mspIdOrg2] = contractsOrg2; logger.info('Initialising submit job queue'); jobQueue = initJobQueue(); - jobQueueWorker = initJobQueueWorker(assetContracts); + jobQueueWorker = initJobQueueWorker(app); if (config.submitJobQueueScheduler === true) { logger.info('Initialising submit job queue scheduler'); jobQueueScheduler = initJobQueueScheduler(); } + app.locals.jobq = jobQueue; - logger.info('Creating REST server'); - const app = await createServer(); - app.set(config.mspIdOrg1, contractsOrg1); - app.set(config.mspIdOrg2, contractsOrg2); - app.set('jobq', jobQueue); - + logger.info('Starting REST server'); app.listen(config.port, () => { logger.info('REST server started on port: %d', config.port); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts index 77dc5fe9..2c021a29 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.router.ts @@ -17,7 +17,7 @@ jobsRouter.get('/:jobId', async (req: Request, res: Response) => { logger.debug('Read request received for job ID %s', jobId); try { - const submitQueue = req.app.get('jobq') as Queue; + const submitQueue = req.app.locals.jobq as Queue; const jobSummary = await getJobSummary(submitQueue, jobId); diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts index e0a60fa7..93e83f8b 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts @@ -11,6 +11,7 @@ import { } from './jobs'; import { Contract, Transaction } from 'fabric-network'; import { mock, MockProxy } from 'jest-mock-extended'; +import { Application } from 'express'; describe('initJobQueue', () => { it.todo('write tests'); @@ -164,6 +165,7 @@ describe('getJobCounts', () => { const mockSavedState = Buffer.from('MOCK SAVED STATE'); let mockTransaction: MockProxy; let mockContract: MockProxy; + let mockApplication: MockProxy; let mockJob: MockProxy; beforeEach(() => { @@ -179,6 +181,9 @@ describe('getJobCounts', () => { .mockReturnValue(mockTransaction); mockContracts.set('mockMspid', mockContract); + mockApplication = mock(); + mockApplication.locals.mockMspid = { assetContract: mockContract }; + mockJob = mock(); }); @@ -188,7 +193,7 @@ describe('getJobCounts', () => { }; const jobResult = await processSubmitTransactionJob( - mockContracts, + mockApplication, mockJob ); @@ -209,7 +214,7 @@ describe('getJobCounts', () => { .mockResolvedValue(mockPayload); const jobResult = await processSubmitTransactionJob( - mockContracts, + mockApplication, mockJob ); @@ -231,7 +236,7 @@ describe('getJobCounts', () => { .mockResolvedValue(mockPayload); const jobResult = await processSubmitTransactionJob( - mockContracts, + mockApplication, mockJob ); @@ -257,7 +262,7 @@ describe('getJobCounts', () => { ); const jobResult = await processSubmitTransactionJob( - mockContracts, + mockApplication, mockJob ); @@ -280,7 +285,7 @@ describe('getJobCounts', () => { .mockRejectedValue(new Error('MOCK ERROR')); await expect(async () => { - await processSubmitTransactionJob(mockContracts, mockJob); + await processSubmitTransactionJob(mockApplication, mockJob); }).rejects.toThrow('MOCK ERROR'); }); }); diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.ts index 2b4f2399..de2ab458 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.ts @@ -6,6 +6,7 @@ */ import { ConnectionOptions, Job, Queue, QueueScheduler, Worker } from 'bullmq'; +import { Application } from 'express'; import { Contract, Transaction } from 'fabric-network'; import * as config from './config'; import { getRetryAction, RetryAction } from './errors'; @@ -69,13 +70,11 @@ export const initJobQueue = (): Queue => { return submitQueue; }; -export const initJobQueueWorker = ( - contracts: Map -): Worker => { +export const initJobQueueWorker = (app: Application): Worker => { const worker = new Worker( config.JOB_QUEUE_NAME, async (job): Promise => { - return await processSubmitTransactionJob(contracts, job); + return await processSubmitTransactionJob(app, job); }, { connection, concurrency: config.submitJobConcurrency } ); @@ -229,12 +228,12 @@ export const getJobCounts = async ( * The job will be retried if this function throws an error */ export const processSubmitTransactionJob = async ( - contracts: Map, + app: Application, job: Job ): Promise => { logger.debug({ jobId: job.id, jobName: job.name }, 'Processing job'); - const contract = contracts.get(job.data.mspid); + const contract = app.locals[job.data.mspid]?.assetContract as Contract; if (contract === undefined) { logger.error( { jobId: job.id, jobName: job.name }, diff --git a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts index 4b729951..d092337d 100644 --- a/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/transactions.router.ts @@ -21,7 +21,7 @@ transactionsRouter.get( logger.debug('Read request received for transaction ID %s', transactionId); try { - const qsccContract = req.app.get(mspId).qsccContract as Contract; + const qsccContract = req.app.locals[mspId]?.qsccContract as Contract; const validationCode = await getTransactionValidationCode( qsccContract, From 5447e3534d783ccf47a59a1d3271edf0978663e2 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 14 Dec 2021 13:42:46 +0000 Subject: [PATCH 097/106] Add node, and npm version requirements Match the versions required in asset-transfer-basic/application-typescript Also update to latest version of fabric-network Signed-off-by: James Taylor --- .../rest-api-typescript/package-lock.json | 107 +++++++++--------- .../rest-api-typescript/package.json | 6 +- 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/package-lock.json b/asset-transfer-basic/rest-api-typescript/package-lock.json index c56206e9..c7d078ae 100644 --- a/asset-transfer-basic/rest-api-typescript/package-lock.json +++ b/asset-transfer-basic/rest-api-typescript/package-lock.json @@ -547,17 +547,18 @@ } }, "@grpc/grpc-js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.4.tgz", - "integrity": "sha512-AxtZcm0mArQhY9z8T3TynCYVEaSKxNCa9mVhVwBCUnsuUEe8Zn94bPYYKVQSLt+hJJ1y0ukr3mUvtWfcATL/IQ==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.4.4.tgz", + "integrity": "sha512-a6222b7Dl6fIlMgzVl7e+NiRoLiZFbpcwvBH2Oli56Bn7W4/3Ld+86hK4ffPn5rx2DlDidmIcvIJiOQXyhv9gA==", "requires": { + "@grpc/proto-loader": "^0.6.4", "@types/node": ">=12.12.47" } }, "@grpc/proto-loader": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.3.tgz", - "integrity": "sha512-AtMWwb7kY8DdtwIQh2hC4YFM1MzZ22lMA+gjbnCYDgICt14vX2tCa59bDrEjFyOI4LvORjpvT/UhHUdKvsX8og==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.7.tgz", + "integrity": "sha512-QzTPIyJxU0u+r2qGe8VMl3j/W2ryhEvBv7hc42OjYfthSj370fUrb7na65rG6w3YLZS/fb8p89iTBobfWGDgdw==", "requires": { "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", @@ -1390,9 +1391,9 @@ } }, "@types/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", + "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==" }, "@types/yargs": { "version": "15.0.14", @@ -1647,9 +1648,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "3.2.1", @@ -1750,11 +1751,11 @@ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" }, "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "requires": { - "follow-redirects": "^1.10.0" + "follow-redirects": "^1.14.0" } }, "axios-cookiejar-support": { @@ -2899,15 +2900,15 @@ "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" }, "fabric-common": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/fabric-common/-/fabric-common-2.2.8.tgz", - "integrity": "sha512-lUOb2Sq645XcfIrtH6jMBaPiPUmFaHqMjGEK7uix1al0ITsNUUvtYD17MJfj/Pr0yhj0KjTI0FF1Ep3ZSL7kXg==", + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/fabric-common/-/fabric-common-2.2.10.tgz", + "integrity": "sha512-0FRY8M906D0B/NGyPKDbLoorhHCaxlus5lv9X7+sf+M/UnzBCQIps5XDhO2KJVyq4hP4XUwgJV8zBBpxSmN3iQ==", "requires": { "callsite": "^1.0.0", "elliptic": "^6.5.4", - "fabric-protos": "2.2.8", + "fabric-protos": "2.2.10", "js-sha3": "^0.8.0", - "jsrsasign": "^8.0.24", + "jsrsasign": "^10.4.1", "long": "^4.0.0", "nconf": "^0.11.2", "pkcs11js": "^1.0.6", @@ -2918,20 +2919,20 @@ } }, "fabric-network": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/fabric-network/-/fabric-network-2.2.8.tgz", - "integrity": "sha512-/kFgTtNA2jqY26HeEpti56G7dPAEef2fX3ebNfL/mAtJxA0Z0YXK3Jwd1N7wGCRRu+lriPd3a0wi7RPIgwAcCw==", + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/fabric-network/-/fabric-network-2.2.10.tgz", + "integrity": "sha512-S6ITwBoLTfR9mokWqmAoHW2++VL1F5NS4LMJKz/tXbCPJcg6JyQGn07/OOHtqESchVKbadzvwrahy93s3CBFmQ==", "requires": { - "fabric-common": "2.2.8", - "fabric-protos": "2.2.8", + "fabric-common": "2.2.10", + "fabric-protos": "2.2.10", "long": "^4.0.0", "nano": "^9.0.3" } }, "fabric-protos": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/fabric-protos/-/fabric-protos-2.2.8.tgz", - "integrity": "sha512-5e3MDLtXdsZpXs92kfTGRirIomaaQ3MaKQ59kp0y9QtYZGced4k9Donl1G3nREoBi0yy1bp45lkDnjRIOG9v+g==", + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/fabric-protos/-/fabric-protos-2.2.10.tgz", + "integrity": "sha512-6ApPgneH/UxsB9QbwPzHEucsCVMnwacyuyHTYxpfj0/ZydWIoNThNsSJEfBdmwhupLG5w5vVup/q/CvhVw3Vmg==", "requires": { "@grpc/grpc-js": "^1.3.4", "@grpc/proto-loader": "^0.6.2", @@ -3101,9 +3102,9 @@ "dev": true }, "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + "version": "1.14.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", + "integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==" }, "form-data": { "version": "3.0.1", @@ -5029,9 +5030,9 @@ } }, "jsrsasign": { - "version": "8.0.24", - "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-8.0.24.tgz", - "integrity": "sha512-u45jAyusqUpyGbFc2IbHoeE4rSkoBWQgLe/w99temHenX+GyCz4nflU5sjK7ajU1ffZTezl6le7u43Yjr/lkQg==" + "version": "10.5.1", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.1.tgz", + "integrity": "sha512-yW0fq87KNZFw4Pn5ySllXs3ztZAROQZczEheKZTqmiNpCe/Xj9r5NhuAQ7MXTOyEZGJ/+MPHGTsfbgPFaLpwHQ==" }, "kleur": { "version": "3.0.3", @@ -5270,15 +5271,15 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", "optional": true }, "nano": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/nano/-/nano-9.0.3.tgz", - "integrity": "sha512-NFI8+6q5ihnozH6qK+BJ+ilnPfZzBhlUswaFgqUvSp2EN5eJ2BMxbzkYiBsN+waa+N95FculCdbneDmzLWfXaQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/nano/-/nano-9.0.5.tgz", + "integrity": "sha512-fEAhwAdXh4hDDnC8cYJtW6D8ivOmpvFAqT90+zEuQREpRkzA/mJPcI4EKv15JUdajaqiLTXNoKK6PaRF+/06DQ==", "requires": { "@types/tough-cookie": "^4.0.0", "axios": "^0.21.1", @@ -5288,9 +5289,9 @@ }, "dependencies": { "qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", + "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", "requires": { "side-channel": "^1.0.4" } @@ -5609,9 +5610,9 @@ } }, "pkcs11js": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/pkcs11js/-/pkcs11js-1.2.5.tgz", - "integrity": "sha512-ZOCi2ZqKV6LprMmODsQKxgxnwGyy5nQ+nbI6QeS1M5B7gaH09xIcz8BomukrtyLHs/z3eQvvzy1SAFYXrYOG4w==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/pkcs11js/-/pkcs11js-1.2.6.tgz", + "integrity": "sha512-G3mgp0jcTO2A0fcqPdHEU4xYsmZgztMH10RmtUzTjf3pWxWaX7K3wTWVZInE6OaBucUS3d6St+8eUkqO44Hi3Q==", "optional": true, "requires": { "nan": "^2.14.2" @@ -6382,9 +6383,9 @@ } }, "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, "to-fast-properties": { @@ -6619,9 +6620,9 @@ } }, "validator": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", - "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==" + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==" }, "vary": { "version": "1.1.2", diff --git a/asset-transfer-basic/rest-api-typescript/package.json b/asset-transfer-basic/rest-api-typescript/package.json index 6a9317ff..c8350cd0 100644 --- a/asset-transfer-basic/rest-api-typescript/package.json +++ b/asset-transfer-basic/rest-api-typescript/package.json @@ -3,13 +3,17 @@ "version": "1.0.0", "description": "Asset Transfer Basic REST API implemented in TypeScript", "main": "dist/index.js", + "engines": { + "node": ">=12", + "npm": ">=5" + }, "dependencies": { "bullmq": "^1.47.2", "dotenv": "^10.0.0", "env-var": "^7.0.1", "express": "^4.17.1", "express-validator": "^6.12.0", - "fabric-network": "^2.2.8", + "fabric-network": "^2.2.10", "helmet": "^4.6.0", "http-status-codes": "^2.1.4", "ioredis": "^4.27.8", From 0208892429dede0190c9d3a8b5bbbf840edf4db1 Mon Sep 17 00:00:00 2001 From: sapthasurendran <48531319+sapthasurendran@users.noreply.github.com> Date: Wed, 15 Dec 2021 15:56:46 +0530 Subject: [PATCH 098/106] Go samples Migration to fabric-gateway (#561) * go packages Signed-off-by: sapthasurendran * Go sample Migration to fabric-gateway Signed-off-by: sapthasurendran lint script changes Signed-off-by: sapthasurendran lint fixes Signed-off-by: sapthasurendran Upgrade go to 1.16 Signed-off-by: sapthasurendran add go mod Signed-off-by: sapthasurendran To match with docs Signed-off-by: sapthasurendran lint updates Signed-off-by: sapthasurendran --- .../application-gateway-go/assetTransfer.go | 276 ++++++++++ .../application-gateway-go/go.mod | 11 + .../application-gateway-go/go.sum | 488 ++++++++++++++++++ 3 files changed, 775 insertions(+) create mode 100755 asset-transfer-basic/application-gateway-go/assetTransfer.go create mode 100644 asset-transfer-basic/application-gateway-go/go.mod create mode 100644 asset-transfer-basic/application-gateway-go/go.sum diff --git a/asset-transfer-basic/application-gateway-go/assetTransfer.go b/asset-transfer-basic/application-gateway-go/assetTransfer.go new file mode 100755 index 00000000..00afba46 --- /dev/null +++ b/asset-transfer-basic/application-gateway-go/assetTransfer.go @@ -0,0 +1,276 @@ +/* +Copyright 2021 IBM All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package main + +import ( + "bytes" + "context" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + "github.com/hyperledger/fabric-gateway/pkg/client" + "github.com/hyperledger/fabric-gateway/pkg/identity" + gwproto "github.com/hyperledger/fabric-protos-go/gateway" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/status" + "io/ioutil" + "log" + "path" + "time" +) + +const ( + mspID = "Org1MSP" + cryptoPath = "../../test-network/organizations/peerOrganizations/org1.example.com" + certPath = cryptoPath + "/users/User1@org1.example.com/msp/signcerts/cert.pem" + keyPath = cryptoPath + "/users/User1@org1.example.com/msp/keystore/" + tlsCertPath = cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt" + peerEndpoint = "localhost:7051" + gatewayPeer = "peer0.org1.example.com" + channelName = "mychannel" + chaincodeName = "basic" +) + +var now = time.Now() +var assetId = fmt.Sprintf("asset%d", now.Unix()*1e3+int64(now.Nanosecond())/1e6) + +func main() { + log.Println("============ application-golang starts ============") + + // The gRPC client connection should be shared by all Gateway connections to this endpoint + clientConnection := newGrpcConnection() + defer clientConnection.Close() + + id := newIdentity() + sign := newSign() + + // Create a Gateway connection for a specific client identity + gateway, err := client.Connect( + id, + client.WithSign(sign), + client.WithClientConnection(clientConnection), + // Default timeouts for different gRPC calls + client.WithEvaluateTimeout(5*time.Second), + client.WithEndorseTimeout(15*time.Second), + client.WithSubmitTimeout(5*time.Second), + client.WithCommitStatusTimeout(1*time.Minute), + ) + if err != nil { + panic(err) + } + defer gateway.Close() + + network := gateway.GetNetwork(channelName) + contract := network.GetContract(chaincodeName) + + fmt.Println("initLedger:") + initLedger(contract) + + fmt.Println("getAllAssets:") + getAllAssets(contract) + + fmt.Println("createAsset:") + createAsset(contract) + + fmt.Println("readAssetByID:") + readAssetByID(contract) + + fmt.Println("transferAssetAsync:") + transferAssetAsync(contract) + + fmt.Println("exampleErrorHandling:") + exampleErrorHandling(contract) + + log.Println("============ application-golang ends ============") +} + +// newGrpcConnection creates a gRPC connection to the Gateway server. +func newGrpcConnection() *grpc.ClientConn { + certificate, err := loadCertificate(tlsCertPath) + if err != nil { + panic(err) + } + + certPool := x509.NewCertPool() + certPool.AddCert(certificate) + transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer) + + connection, err := grpc.Dial(peerEndpoint, grpc.WithTransportCredentials(transportCredentials)) + if err != nil { + panic(fmt.Errorf("failed to create gRPC connection: %w", err)) + } + + return connection +} + +// newIdentity creates a client identity for this Gateway connection using an X.509 certificate. +func newIdentity() *identity.X509Identity { + certificate, err := loadCertificate(certPath) + if err != nil { + panic(err) + } + + id, err := identity.NewX509Identity(mspID, certificate) + if err != nil { + panic(err) + } + + return id +} + +func loadCertificate(filename string) (*x509.Certificate, error) { + certificatePEM, err := ioutil.ReadFile(filename) + if err != nil { + return nil, fmt.Errorf("failed to read certificate file: %w", err) + } + return identity.CertificateFromPEM(certificatePEM) +} + +// newSign creates a function that generates a digital signature from a message digest using a private key. +func newSign() identity.Sign { + files, err := ioutil.ReadDir(keyPath) + if err != nil { + panic(fmt.Errorf("failed to read private key directory: %w", err)) + } + privateKeyPEM, err := ioutil.ReadFile(path.Join(keyPath, files[0].Name())) + + if err != nil { + panic(fmt.Errorf("failed to read private key file: %w", err)) + } + + privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM) + if err != nil { + panic(err) + } + + sign, err := identity.NewPrivateKeySign(privateKey) + if err != nil { + panic(err) + } + + return sign +} + +/* + This type of transaction would typically only be run once by an application the first time it was started after its + initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function. +*/ +func initLedger(contract *client.Contract) { + fmt.Printf("Submit Transaction: InitLedger, function creates the initial set of assets on the ledger \n") + + _, err := contract.SubmitTransaction("InitLedger") + if err != nil { + panic(fmt.Errorf("failed to submit transaction: %w", err)) + } + + fmt.Printf("*** Transaction committed successfully\n") +} + +// Evaluate a transaction to query ledger state. +func getAllAssets(contract *client.Contract) { + fmt.Println("Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger") + + evaluateResult, err := contract.EvaluateTransaction("GetAllAssets") + if err != nil { + panic(fmt.Errorf("failed to evaluate transaction: %w", err)) + } + result := formatJSON(evaluateResult) + + fmt.Printf("*** Result:%s\n", result) +} + +// Submit a transaction synchronously, blocking until it has been committed to the ledger. +func createAsset(contract *client.Contract) { + fmt.Printf("Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments \n") + + _, err := contract.SubmitTransaction("CreateAsset", assetId, "yellow", "5", "Tom", "1300") + if err != nil { + panic(fmt.Errorf("failed to submit transaction: %w", err)) + } + + fmt.Printf("*** Transaction committed successfully\n") +} + +// Evaluate a transaction by assetID to query ledger state. +func readAssetByID(contract *client.Contract) { + fmt.Printf("Evaluate Transaction: ReadAsset, function returns asset attributes\n") + + evaluateResult, err := contract.EvaluateTransaction("ReadAsset", assetId) + if err != nil { + panic(fmt.Errorf("failed to evaluate transaction: %w", err)) + } + result := formatJSON(evaluateResult) + + fmt.Printf("*** Result:%s\n", result) +} + +/* +Submit transaction asynchronously, blocking until the transaction has been sent to the orderer, and allowing +this thread to process the chaincode response (e.g. update a UI) without waiting for the commit notification +*/ +func transferAssetAsync(contract *client.Contract) { + fmt.Printf("Async Submit Transaction: TransferAsset, updates existing asset owner'\n") + + submitResult, commit, err := contract.SubmitAsync("TransferAsset", client.WithArguments(assetId, "Mark")) + if err != nil { + panic(fmt.Errorf("failed to submit transaction asynchronously: %w", err)) + } + + fmt.Printf("Successfully submitted transaction to transfer ownership from %s to Mark. \n", string(submitResult)) + fmt.Println("Waiting for transaction commit.") + + if status, err := commit.Status(); err != nil { + panic(fmt.Errorf("failed to get commit status: %w", err)) + } else if !status.Successful { + panic(fmt.Errorf("transaction %s failed to commit with status: %d", status.TransactionID, int32(status.Code))) + } + + fmt.Printf("*** Transaction committed successfully\n") +} + +// Submit transaction, passing in the wrong number of arguments ,expected to throw an error containing details of any error responses from the smart contract. +func exampleErrorHandling(contract *client.Contract) { + fmt.Println("Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error") + + _, err := contract.SubmitTransaction("UpdateAsset") + if err != nil { + switch err := err.(type) { + case *client.EndorseError: + fmt.Printf("Endorse error with gRPC status %v: %s\n", status.Code(err), err) + case *client.SubmitError: + fmt.Printf("Submit error with gRPC status %v: %s\n", status.Code(err), err) + case *client.CommitStatusError: + if errors.Is(err, context.DeadlineExceeded) { + fmt.Printf("Timeout waiting for transaction %s commit status: %s", err.TransactionID, err) + } else { + fmt.Printf("Error obtaining commit status with gRPC status %v: %s\n", status.Code(err), err) + } + case *client.CommitError: + fmt.Printf("Transaction %s failed to commit with status %d: %s\n", err.TransactionID, int32(err.Code), err) + } + /* + Any error that originates from a peer or orderer node external to the gateway will have its details + embedded within the gRPC status error. The following code shows how to extract that. + */ + statusErr := status.Convert(err) + for _, detail := range statusErr.Details() { + errDetail := detail.(*gwproto.ErrorDetail) + fmt.Printf("Error from endpoint: %s, mspId: %s, message: %s\n", errDetail.Address, errDetail.MspId, errDetail.Message) + } + } +} + +//Format JSON data +func formatJSON(data []byte) string { + var prettyJSON bytes.Buffer + if err := json.Indent(&prettyJSON, data, " ", ""); err != nil { + panic(fmt.Errorf("failed to parse JSON: %w", err)) + } + return prettyJSON.String() +} \ No newline at end of file diff --git a/asset-transfer-basic/application-gateway-go/go.mod b/asset-transfer-basic/application-gateway-go/go.mod new file mode 100644 index 00000000..b066448d --- /dev/null +++ b/asset-transfer-basic/application-gateway-go/go.mod @@ -0,0 +1,11 @@ +module assetTransfer + +go 1.16 + +require ( + github.com/hyperledger/fabric-gateway v1.0.0 + github.com/hyperledger/fabric-protos-go v0.0.0-20211118165945-23d738fc3553 + golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect + golang.org/x/text v0.3.7 // indirect + google.golang.org/grpc v1.42.0 +) diff --git a/asset-transfer-basic/application-gateway-go/go.sum b/asset-transfer-basic/application-gateway-go/go.sum new file mode 100644 index 00000000..06b6128c --- /dev/null +++ b/asset-transfer-basic/application-gateway-go/go.sum @@ -0,0 +1,488 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.27.2 h1:1EyY1dsxNDUQEv0O/4TsjosHI2CgB1uo9H/v56xzTxc= +github.com/Shopify/sarama v1.27.2/go.mod h1:g5s5osgELxgM+Md9Qni9rzo7Rbt+vvFQI4bt/Mc93II= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cucumber/gherkin-go/v19 v19.0.3/go.mod h1:jY/NP6jUtRSArQQJ5h1FXOUgk5fZK24qtE7vKi776Vw= +github.com/cucumber/godog v0.12.1/go.mod h1:u6SD7IXC49dLpPN35kal0oYEjsXZWee4pW6Tm9t5pIc= +github.com/cucumber/messages-go/v16 v16.0.0/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g= +github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.10.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v1.3.0/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8= +github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hyperledger/fabric v2.1.1+incompatible h1:cYYRv3vVg4kA6DmrixLxwn1nwBEUuYda8DsMwlaMKbY= +github.com/hyperledger/fabric v2.1.1+incompatible/go.mod h1:tGFAOCT696D3rG0Vofd2dyWYLySHlh0aQjf7Q1HAju0= +github.com/hyperledger/fabric-amcl v0.0.0-20200424173818-327c9e2cf77a h1:JAKZdGuUIjVmES0X31YUD7UqMR2rz/kxLluJuGvsXPk= +github.com/hyperledger/fabric-amcl v0.0.0-20200424173818-327c9e2cf77a/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= +github.com/hyperledger/fabric-gateway v1.0.0 h1:bki1JYYdQzRGHFArxtgG4wyH6sbFNbYn3PzpdeDfjdk= +github.com/hyperledger/fabric-gateway v1.0.0/go.mod h1:uaRZyC+xzfucPqZIJpesdEsugVvChPhDxZiZmDRSFd4= +github.com/hyperledger/fabric-protos-go v0.0.0-20211118165945-23d738fc3553 h1:E9f0v1q4EDfrE+0LdkxVtdYKAZ7PGCaj1bBx45R9yEQ= +github.com/hyperledger/fabric-protos-go v0.0.0-20211118165945-23d738fc3553/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.0 h1:wJbzvpYMVGG9iTI9VxpnNZfd4DzMPoCWze3GgSqz8yg= +github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= +github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= +github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/sykesm/zap-logfmt v0.0.4 h1:U2WzRvmIWG1wDLCFY3sz8UeEmsdHQjHFNlIdmroVFaI= +github.com/sykesm/zap-logfmt v0.0.4/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 h1:WecRHqgE09JBkh/584XIE6PMz5KKE/vER4izNUi30AQ= +golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0 h1:a9tsXlIDD9SKxotJMK3niV7rPZAJeX2aD/0yg3qlIrg= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From dfe79f7fb48c1033511a5ad02bd2cb7e18ee77dc Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 15 Dec 2021 11:50:05 +0000 Subject: [PATCH 099/106] Add comments to jobs.ts Signed-off-by: James Taylor --- .../rest-api-typescript/src/jobs.ts | 270 ++++++++++-------- 1 file changed, 144 insertions(+), 126 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.ts index de2ab458..c46af0e5 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.ts @@ -26,7 +26,6 @@ export type JobResult = { transactionError?: string; }; -// TODO include attempts made? export type JobSummary = { jobId: string; transactionIds: string[]; @@ -53,6 +52,9 @@ const connection: ConnectionOptions = { password: config.redisPassword, }; +/* + * Set up the queue for submit jobs + */ export const initJobQueue = (): Queue => { const submitQueue = new Queue(config.JOB_QUEUE_NAME, { connection, @@ -70,6 +72,10 @@ export const initJobQueue = (): Queue => { return submitQueue; }; +/* + * Set up a worker to process submit jobs on the queue, using the + * processSubmitTransactionJob function below + */ export const initJobQueueWorker = (app: Application): Worker => { const worker = new Worker( config.JOB_QUEUE_NAME, @@ -80,7 +86,7 @@ export const initJobQueueWorker = (app: Application): Worker => { ); worker.on('failed', (job) => { - logger.error({ job }, 'Job failed'); // WHY?! + logger.warn({ job }, 'Job failed'); }); // Important: need to handle this error otherwise worker may stop @@ -98,130 +104,6 @@ export const initJobQueueWorker = (app: Application): Worker => { return worker; }; -export const initJobQueueScheduler = (): QueueScheduler => { - const queueScheduler = new QueueScheduler(config.JOB_QUEUE_NAME, { - connection, - }); - - queueScheduler.on('failed', (jobId, failedReason) => { - // TODO when does this happen, and how should it be handled? - logger.error({ jobId, failedReason }, 'Queue sceduler failure'); - }); - - return queueScheduler; -}; - -export const addSubmitTransactionJob = async ( - submitQueue: Queue, - mspid: string, - transactionName: string, - ...transactionArgs: string[] -): Promise => { - const jobName = `submit ${transactionName} transaction`; - const job = await submitQueue.add(jobName, { - mspid, - transactionName, - transactionArgs: transactionArgs, - transactionIds: [], - }); - - if (job?.id === undefined) { - throw new Error('Submit transaction job ID not available'); - } - - return job.id; -}; - -/* - * Gets a summary for the jobs endpoint - */ -export const getJobSummary = async ( - queue: Queue, - jobId: string -): Promise => { - const job: Job | undefined = await queue.getJob(jobId); - logger.debug({ job }, 'Got job'); - - if (!(job && job.id != undefined)) { - throw new JobNotFoundError(`Job ${jobId} not found`, jobId); - } - - let transactionIds: string[]; - if (job.data && job.data.transactionIds) { - transactionIds = job.data.transactionIds; - } else { - transactionIds = []; - } - - let transactionError; - let transactionPayload; - const returnValue = job.returnvalue; - if (returnValue) { - if (returnValue.transactionError) { - transactionError = returnValue.transactionError; - } - - if ( - returnValue.transactionPayload && - returnValue.transactionPayload.length > 0 - ) { - transactionPayload = returnValue.transactionPayload.toString(); - } else { - transactionPayload = ''; - } - } - - const jobSummary: JobSummary = { - jobId: job.id, - transactionIds, - transactionError, - transactionPayload, - }; - - return jobSummary; -}; - -export const updateJobData = async ( - job: Job, - transaction: Transaction | undefined -): Promise => { - const newData = { ...job.data }; - - if (transaction != undefined) { - const transationIds = ([] as string[]).concat( - newData.transactionIds, - transaction.getTransactionId() - ); - newData.transactionIds = transationIds; - - newData.transactionState = transaction.serialize(); - } else { - newData.transactionState = undefined; - } - - await job.update(newData); -}; - -/* - * Get the current job counts - * - * This function is used for the liveness REST endpoint - */ -export const getJobCounts = async ( - queue: Queue -): Promise<{ [index: string]: number }> => { - const jobCounts = await queue.getJobCounts( - 'active', - 'completed', - 'delayed', - 'failed', - 'waiting' - ); - logger.debug({ jobCounts }, 'Current job counts'); - - return jobCounts; -}; - /* * Process a submit transaction request from the job queue * @@ -326,3 +208,139 @@ export const processSubmitTransactionJob = async ( throw err; } }; + +/* + * Set up a scheduler for the submit job queue + * + * This manages stalled and delayed jobs and is required for retries with backoff + */ +export const initJobQueueScheduler = (): QueueScheduler => { + const queueScheduler = new QueueScheduler(config.JOB_QUEUE_NAME, { + connection, + }); + + queueScheduler.on('failed', (jobId, failedReason) => { + logger.error({ jobId, failedReason }, 'Queue sceduler failure'); + }); + + return queueScheduler; +}; + +/* + * Helper to add a new submit transaction job to the queue + */ +export const addSubmitTransactionJob = async ( + submitQueue: Queue, + mspid: string, + transactionName: string, + ...transactionArgs: string[] +): Promise => { + const jobName = `submit ${transactionName} transaction`; + const job = await submitQueue.add(jobName, { + mspid, + transactionName, + transactionArgs: transactionArgs, + transactionIds: [], + }); + + if (job?.id === undefined) { + throw new Error('Submit transaction job ID not available'); + } + + return job.id; +}; + +/* + * Helper to update the data for an existing job + */ +export const updateJobData = async ( + job: Job, + transaction: Transaction | undefined +): Promise => { + const newData = { ...job.data }; + + if (transaction != undefined) { + const transationIds = ([] as string[]).concat( + newData.transactionIds, + transaction.getTransactionId() + ); + newData.transactionIds = transationIds; + + newData.transactionState = transaction.serialize(); + } else { + newData.transactionState = undefined; + } + + await job.update(newData); +}; + +/* + * Gets a job summary + * + * This function is used for the jobs REST endpoint + */ +export const getJobSummary = async ( + queue: Queue, + jobId: string +): Promise => { + const job: Job | undefined = await queue.getJob(jobId); + logger.debug({ job }, 'Got job'); + + if (!(job && job.id != undefined)) { + throw new JobNotFoundError(`Job ${jobId} not found`, jobId); + } + + let transactionIds: string[]; + if (job.data && job.data.transactionIds) { + transactionIds = job.data.transactionIds; + } else { + transactionIds = []; + } + + let transactionError; + let transactionPayload; + const returnValue = job.returnvalue; + if (returnValue) { + if (returnValue.transactionError) { + transactionError = returnValue.transactionError; + } + + if ( + returnValue.transactionPayload && + returnValue.transactionPayload.length > 0 + ) { + transactionPayload = returnValue.transactionPayload.toString(); + } else { + transactionPayload = ''; + } + } + + const jobSummary: JobSummary = { + jobId: job.id, + transactionIds, + transactionError, + transactionPayload, + }; + + return jobSummary; +}; + +/* + * Get the current job counts + * + * This function is used for the liveness REST endpoint + */ +export const getJobCounts = async ( + queue: Queue +): Promise<{ [index: string]: number }> => { + const jobCounts = await queue.getJobCounts( + 'active', + 'completed', + 'delayed', + 'failed', + 'waiting' + ); + logger.debug({ jobCounts }, 'Current job counts'); + + return jobCounts; +}; From fce803af246a9c6ce2e95bb26221a9042c6a0138 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Wed, 15 Dec 2021 12:36:18 +0000 Subject: [PATCH 100/106] Add jobs spec tests Signed-off-by: James Taylor --- .../rest-api-typescript/src/jobs.spec.ts | 87 +++++++++++++++---- .../rest-api-typescript/src/jobs.ts | 4 +- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts index 93e83f8b..1d8b7fe2 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.spec.ts @@ -4,29 +4,54 @@ import { Job, Queue } from 'bullmq'; import { + addSubmitTransactionJob, getJobCounts, getJobSummary, processSubmitTransactionJob, JobNotFoundError, + updateJobData, } from './jobs'; import { Contract, Transaction } from 'fabric-network'; import { mock, MockProxy } from 'jest-mock-extended'; import { Application } from 'express'; -describe('initJobQueue', () => { - it.todo('write tests'); -}); - -describe('initJobQueueWorker', () => { - it.todo('write tests'); -}); - -describe('initJobQueueScheduler', () => { - it.todo('write tests'); -}); - describe('addSubmitTransactionJob', () => { - it.todo('write tests'); + let mockJob: MockProxy; + let mockQueue: MockProxy; + + beforeEach(() => { + mockJob = mock(); + mockQueue = mock(); + mockQueue.add.mockResolvedValue(mockJob); + }); + + it('returns the new job ID', async () => { + mockJob.id = 'mockJobId'; + + const jobid = await addSubmitTransactionJob( + mockQueue, + 'mockMspId', + 'txn', + 'arg1', + 'arg2' + ); + + expect(jobid).toBe('mockJobId'); + }); + + it('throws an error if there is no job ID', async () => { + mockJob.id = undefined; + + await expect(async () => { + await addSubmitTransactionJob( + mockQueue, + 'mockMspId', + 'txn', + 'arg1', + 'arg2' + ); + }).rejects.toThrowError('Submit transaction job ID not available'); + }); }); describe('getJobSummary', () => { @@ -133,8 +158,40 @@ describe('getJobSummary', () => { }); }); -describe('updateSubmitTransactionJobStateData', () => { - it.todo('write tests'); +describe('updateJobData', () => { + let mockJob: MockProxy; + + beforeEach(() => { + mockJob = mock(); + mockJob.data = { + transactionIds: ['txn1'], + }; + }); + + it('stores the serialized state in the job data if a transaction is specified', async () => { + const mockSavedState = Buffer.from('MOCK SAVED STATE'); + const mockTransaction = mock(); + mockTransaction.getTransactionId.mockReturnValue('txn2'); + mockTransaction.serialize.mockReturnValue(mockSavedState); + + await updateJobData(mockJob, mockTransaction); + + expect(mockJob.update).toBeCalledTimes(1); + expect(mockJob.update).toBeCalledWith({ + transactionIds: ['txn1', 'txn2'], + transactionState: mockSavedState, + }); + }); + + it('removes the serialized state from the job data if a transaction is not specified', async () => { + await updateJobData(mockJob, undefined); + + expect(mockJob.update).toBeCalledTimes(1); + expect(mockJob.update).toBeCalledWith({ + transactionIds: ['txn1'], + transactionState: undefined, + }); + }); }); describe('getJobCounts', () => { diff --git a/asset-transfer-basic/rest-api-typescript/src/jobs.ts b/asset-transfer-basic/rest-api-typescript/src/jobs.ts index c46af0e5..64307982 100644 --- a/asset-transfer-basic/rest-api-typescript/src/jobs.ts +++ b/asset-transfer-basic/rest-api-typescript/src/jobs.ts @@ -53,7 +53,7 @@ const connection: ConnectionOptions = { }; /* - * Set up the queue for submit jobs + * Set up the queue for submit jobs */ export const initJobQueue = (): Queue => { const submitQueue = new Queue(config.JOB_QUEUE_NAME, { @@ -276,7 +276,7 @@ export const updateJobData = async ( /* * Gets a job summary - * + * * This function is used for the jobs REST endpoint */ export const getJobSummary = async ( From af2f6e005c3a3380a21795d99c38139bad088bc2 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Tue, 14 Dec 2021 12:20:49 +0000 Subject: [PATCH 101/106] Prepare REST sample for fabric-samples repository Signed-off-by: James Taylor --- .github/workflows/publish.yaml | 54 ----- .gitignore | 1 - LICENSE | 201 ------------------ README.md | 52 ----- .../rest-api-typescript/README.md | 6 +- 5 files changed, 3 insertions(+), 311 deletions(-) delete mode 100644 .github/workflows/publish.yaml delete mode 100644 .gitignore delete mode 100644 LICENSE delete mode 100644 README.md diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml deleted file mode 100644 index d24714b2..00000000 --- a/.github/workflows/publish.yaml +++ /dev/null @@ -1,54 +0,0 @@ -name: fabric-rest-sample - -on: - push: - # Publish `main` as Docker `latest` image. - branches: - - main - - # Publish `v1.2.3` tags as releases. - tags: - - v* - - # Run tests for any PRs. - pull_request: - -env: - IMAGE_NAME: fabric-rest-sample - SOURCE_FOLDER: asset-transfer-basic/rest-api-typescript - -jobs: - # Push image to GitHub Packages. - # See also https://docs.docker.com/docker-hub/builds/ - push: - runs-on: ubuntu-latest - permissions: - packages: write - contents: read - - steps: - - uses: actions/checkout@v2 - - - name: Build image - run: docker build --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" $SOURCE_FOLDER - - - name: Log in to registry - # This is where you will update the PAT to GITHUB_TOKEN - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - - name: Push image - run: | - IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME - - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - # Strip git ref prefix from version - VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') - # Strip "v" prefix from tag name - [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') - # Use Docker `latest` tag convention - [ "$VERSION" == "main" ] && VERSION=latest - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - docker tag $IMAGE_NAME $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b0b21603..00000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -local.http diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9e..00000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md deleted file mode 100644 index 076cf6c8..00000000 --- a/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Fabric REST sample - -Prototype sample REST server to demonstrate good Fabric Node SDK practices for parts of [FAB-18511](https://jira.hyperledger.org/browse/FAB-18511) - -The intention is to deliver the sample to the [asset-transfer-basic/rest-api-typescript directory of the fabric-samples repository](https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-basic) - -See the [sample readme for usage intructions](asset-transfer-basic/rest-api-typescript/README.md) - -## Overview - -The primary aim of this sample is to show how to write a long running client application using the Fabric Node SDK, i.e. without reconnecting for each transaction - -It should also show: - -- basic transaction retries -- long running event handling -- requests from multiple users - -## Next steps - -### Handling transaction errors - -Should transactions be retried _unless they fail_ with specific errors, e.g. duplicate transaction (the current implementation)? - -**or** - -Should transactions be retried _when they fail_ with specific errors? - -Also, transactions are currently only retried if they are successfully endorsed- does that seem reasonable? - -If the transaction failed because of MVCC_READ_CONFLICT, is a chance that it could pass when retrying? (Is MVCC_READ_CONFLICT an endorsement error?) - -### Handling other errors - -Need to make sure it's clear what went wrong and fail properly it necessary, for example when starting without a redis instance - -### Finish off unit tests - -Coverage is looking much better now but there are a few more todos - -### More comments - -Need to document what's going on and why, especially in the fabric.ts file! - -### Feedback - -- More people trying out the sample (and ideally trying to break it a bit!) -- Code review to merge sample into fabric-samples - -### Known problems - -See [issues](https://github.com/hyperledgendary/fabric-rest-sample/issues) diff --git a/asset-transfer-basic/rest-api-typescript/README.md b/asset-transfer-basic/rest-api-typescript/README.md index fda1e708..5bcb1f17 100644 --- a/asset-transfer-basic/rest-api-typescript/README.md +++ b/asset-transfer-basic/rest-api-typescript/README.md @@ -27,11 +27,11 @@ See [src/index.ts](src/index.ts) for a description of the sample code structure, ## Usage -**Note:** these instructions should work with the main branch of `fabric-samples` - To build and start the sample REST server, you'll need to [download and install an LTS version of node](https://nodejs.org/en/download/) -Clone this repository and change to the `fabric-rest-sample/asset-transfer-basic/rest-api-typescript` directory before running the following commands +Clone the `fabric-samples` repository and change to the `fabric-samples/asset-transfer-basic/rest-api-typescript` directory before running the following commands + +**Note:** these instructions should work with the main branch of `fabric-samples` Install dependencies From ad20a5178dfe0ab867f66b29bf57a362b4751cc4 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Thu, 16 Dec 2021 11:37:05 +0000 Subject: [PATCH 102/106] Add build status to readme (#564) Signed-off-by: James Taylor --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1b5ba6c6..96dd5463 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ # Hyperledger Fabric Samples +[![Build Status](https://dev.azure.com/Hyperledger/Fabric-Samples/_apis/build/status/Fabric-Samples?branchName=main)](https://dev.azure.com/Hyperledger/Fabric-Samples/_build/latest?definitionId=28&branchName=main) + You can use Fabric samples to get started working with Hyperledger Fabric, explore important Fabric features, and learn how to build applications that can interact with blockchain networks using the Fabric SDKs. To learn more about Hyperledger Fabric, visit the [Fabric documentation](https://hyperledger-fabric.readthedocs.io/en/latest). ## Getting started with the Fabric samples From 96623f1bd5949bde4bfee80a6352e36d2d1b7d5b Mon Sep 17 00:00:00 2001 From: Matthew B White Date: Fri, 17 Dec 2021 13:18:22 +0000 Subject: [PATCH 103/106] Adding examples of CCAAS and support into the test-network (#560) - Updated the test-network with examples of runnig CCAAS - Updating the asset transfer basic with how to run chaincode as a service. Signed-off-by: Matthew B White --- .gitignore | 2 +- .../chaincode-java/Dockerfile | 31 + .../chaincode-java/build.gradle | 4 +- .../docker/docker-entrypoint.sh | 16 + .../chaincode-typescript/Dockerfile | 34 + .../docker/docker-entrypoint.sh | 16 + .../chaincode-typescript/npm-shrinkwrap.json | 5172 +++++++++++++++++ .../chaincode-typescript/package.json | 15 +- .../CHAINCODE_AS_A_SERVICE_TUTORIAL.md | 204 + test-network/README.md | 8 +- .../docker/docker-compose-test-net.yaml | 4 + test-network/monitordocker.sh | 33 + test-network/network.sh | 38 +- test-network/scripts/ccutils.sh | 165 + test-network/scripts/deployCC.sh | 164 +- test-network/scripts/deployCCAAS.sh | 206 + test-network/scripts/pkgcc.sh | 107 + test-network/scripts/utils.sh | 23 + 18 files changed, 6058 insertions(+), 184 deletions(-) create mode 100755 asset-transfer-basic/chaincode-java/Dockerfile create mode 100755 asset-transfer-basic/chaincode-java/docker/docker-entrypoint.sh create mode 100644 asset-transfer-basic/chaincode-typescript/Dockerfile create mode 100755 asset-transfer-basic/chaincode-typescript/docker/docker-entrypoint.sh create mode 100644 asset-transfer-basic/chaincode-typescript/npm-shrinkwrap.json create mode 100644 test-network/CHAINCODE_AS_A_SERVICE_TUTORIAL.md create mode 100755 test-network/monitordocker.sh create mode 100644 test-network/scripts/ccutils.sh create mode 100755 test-network/scripts/deployCCAAS.sh create mode 100755 test-network/scripts/pkgcc.sh diff --git a/.gitignore b/.gitignore index 9e2d7d0e..53ee01b9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ # Vim file artifacts .*.sw* # installed platform-specific binaries -/bin +bin /config .DS_Store .project diff --git a/asset-transfer-basic/chaincode-java/Dockerfile b/asset-transfer-basic/chaincode-java/Dockerfile new file mode 100755 index 00000000..79ade7a5 --- /dev/null +++ b/asset-transfer-basic/chaincode-java/Dockerfile @@ -0,0 +1,31 @@ +# the first stage +FROM gradle:jdk11 AS GRADLE_BUILD +ARG CC_SERVER_PORT + +# copy the build.gradle and src code to the container +COPY src/ src/ +COPY build.gradle ./ + +# Build and package our code +RUN gradle --no-daemon build shadowJar -x checkstyleMain -x checkstyleTest + + +# the second stage of our build just needs the compiled files +FROM openjdk:11-jre + +# Setup tini to work better handle signals +ENV TINI_VERSION v0.19.0 +ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini +RUN chmod +x /tini + +RUN addgroup --system javauser && useradd -g javauser javauser + +# copy only the artifacts we need from the first stage and discard the rest +COPY --chown=javauser:javauser --from=GRADLE_BUILD /home/gradle/build/libs/chaincode.jar /chaincode.jar +COPY --chown=javauser:javauser docker/docker-entrypoint.sh /docker-entrypoint.sh + +ENV PORT $CC_SERVER_PORT +EXPOSE $CC_SERVER_PORT + +USER javauser +ENTRYPOINT [ "/tini", "--", "/docker-entrypoint.sh" ] diff --git a/asset-transfer-basic/chaincode-java/build.gradle b/asset-transfer-basic/chaincode-java/build.gradle index 41183acd..f6632b38 100644 --- a/asset-transfer-basic/chaincode-java/build.gradle +++ b/asset-transfer-basic/chaincode-java/build.gradle @@ -14,10 +14,10 @@ version '1.0-SNAPSHOT' dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.4.1' implementation 'org.json:json:+' implementation 'com.owlike:genson:1.5' - testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+' + testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.4.1' testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' testImplementation 'org.assertj:assertj-core:3.11.1' testImplementation 'org.mockito:mockito-core:2.+' diff --git a/asset-transfer-basic/chaincode-java/docker/docker-entrypoint.sh b/asset-transfer-basic/chaincode-java/docker/docker-entrypoint.sh new file mode 100755 index 00000000..7192c8da --- /dev/null +++ b/asset-transfer-basic/chaincode-java/docker/docker-entrypoint.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# +# SPDX-License-Identifier: Apache-2.0 +# +set -euo pipefail +: ${CORE_PEER_TLS_ENABLED:="false"} +: ${DEBUG:="false"} + +if [ "${DEBUG,,}" = "true" ]; then + java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 -jar /chaincode.jar +elif [ "${CORE_PEER_TLS_ENABLED,,}" = "true" ]; then + java -jar /chaincode.jar # todo +else + java -jar /chaincode.jar +fi + diff --git a/asset-transfer-basic/chaincode-typescript/Dockerfile b/asset-transfer-basic/chaincode-typescript/Dockerfile new file mode 100644 index 00000000..22c35459 --- /dev/null +++ b/asset-transfer-basic/chaincode-typescript/Dockerfile @@ -0,0 +1,34 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +FROM node:16 AS builder +ARG CC_SERVER_PORT + +WORKDIR /usr/src/app + +# Copy node.js source and build, changing owner as well +COPY --chown=node:node . /usr/src/app +RUN npm ci && npm run package + + +FROM node:16 AS production + +# Setup tini to work better handle signals +ENV TINI_VERSION v0.19.0 +ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini +RUN chmod +x /tini + + +WORKDIR /usr/src/app +COPY --chown=node:node --from=builder /usr/src/app/dist ./dist +COPY --chown=node:node --from=builder /usr/src/app/package.json ./ +COPY --chown=node:node --from=builder /usr/src/app/npm-shrinkwrap.json ./ +COPY --chown=node:node docker/docker-entrypoint.sh /usr/src/app/docker-entrypoint.sh +RUN npm ci --only=production + +ENV PORT $CC_SERVER_PORT +EXPOSE $CC_SERVER_PORT +ENV NODE_ENV=production + +USER node +ENTRYPOINT [ "/tini", "--", "/usr/src/app/docker-entrypoint.sh" ] diff --git a/asset-transfer-basic/chaincode-typescript/docker/docker-entrypoint.sh b/asset-transfer-basic/chaincode-typescript/docker/docker-entrypoint.sh new file mode 100755 index 00000000..2fd8fcf6 --- /dev/null +++ b/asset-transfer-basic/chaincode-typescript/docker/docker-entrypoint.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# +# SPDX-License-Identifier: Apache-2.0 +# +set -euo pipefail +: ${CORE_PEER_TLS_ENABLED:="false"} +: ${DEBUG:="false"} + +if [ "${DEBUG,,}" = "true" ]; then + npm run start:server-debug +elif [ "${CORE_PEER_TLS_ENABLED,,}" = "true" ]; then + npm run start:server +else + npm run start:server-nontls +fi + diff --git a/asset-transfer-basic/chaincode-typescript/npm-shrinkwrap.json b/asset-transfer-basic/chaincode-typescript/npm-shrinkwrap.json new file mode 100644 index 00000000..3e3a40fd --- /dev/null +++ b/asset-transfer-basic/chaincode-typescript/npm-shrinkwrap.json @@ -0,0 +1,5172 @@ +{ + "name": "asset-transfer-basic", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "asset-transfer-basic", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "fabric-contract-api": "^2.4.0", + "fabric-shim": "^2.4.0", + "json-stringify-deterministic": "^1.0.1", + "sort-keys-recursive": "^2.1.2" + }, + "devDependencies": { + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.5", + "@types/node": "^10.12.10", + "@types/sinon": "^5.0.7", + "@types/sinon-chai": "^3.2.1", + "chai": "^4.2.0", + "mocha": "^5.2.0", + "nyc": "^14.1.1", + "sinon": "^7.1.1", + "sinon-chai": "^3.3.0", + "ts-node": "^7.0.1", + "tslint": "^5.11.0", + "typescript": "^3.1.6" + }, + "engines": { + "node": ">=12", + "npm": ">=5" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", + "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz", + "integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", + "integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.16.0", + "@babel/template": "^7.16.0", + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz", + "integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz", + "integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz", + "integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", + "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.15.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.4.tgz", + "integrity": "sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz", + "integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.0", + "@babel/parser": "^7.16.0", + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz", + "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.0", + "@babel/generator": "^7.16.0", + "@babel/helper-function-name": "^7.16.0", + "@babel/helper-hoist-variables": "^7.16.0", + "@babel/helper-split-export-declaration": "^7.16.0", + "@babel/parser": "^7.16.3", + "@babel/types": "^7.16.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", + "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.15.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@fidm/asn1": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", + "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@fidm/x509": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", + "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", + "dependencies": { + "@fidm/asn1": "^1.0.4", + "tweetnacl": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.4.4.tgz", + "integrity": "sha512-a6222b7Dl6fIlMgzVl7e+NiRoLiZFbpcwvBH2Oli56Bn7W4/3Ld+86hK4ffPn5rx2DlDidmIcvIJiOQXyhv9gA==", + "dependencies": { + "@grpc/proto-loader": "^0.6.4", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/@types/node": { + "version": "16.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", + "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==" + }, + "node_modules/@grpc/proto-loader": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.7.tgz", + "integrity": "sha512-QzTPIyJxU0u+r2qGe8VMl3j/W2ryhEvBv7hc42OjYfthSj370fUrb7na65rG6w3YLZS/fb8p89iTBobfWGDgdw==", + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.1.1" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", + "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", + "dev": true + }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "node_modules/@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "node_modules/@types/sinon": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-5.0.7.tgz", + "integrity": "sha512-opwMHufhUwkn/UUDk35LDbKJpA2VBsZT8WLU8NjayvRLGPxQkN+8XmfC2Xl35MAscBE8469koLLBjaI3XLEIww==", + "dev": true + }, + "node_modules/@types/sinon-chai": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.6.tgz", + "integrity": "sha512-Z57LprQ+yOQNu9d6mWdHNvnmncPXzDWGSeLj+8L075/QahToapC4Q13zAFRVKV4clyBmdJ5gz4xBfVkOso5lXw==", + "dev": true, + "dependencies": { + "@types/chai": "*", + "@types/sinon": "*" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "dependencies": { + "default-require-extensions": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/async": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "dependencies": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/class-transformer": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", + "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cp-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", + "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "make-dir": "^2.0.0", + "nested-error-stacks": "^2.0.0", + "pify": "^4.0.1", + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "dependencies": { + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fabric-contract-api": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.4.1.tgz", + "integrity": "sha512-gFnr3beEnqOdzWEtkcf5O5hkVPWQHURA+Uunr9eZzfV+s5sgpewiIH/VhO8a9Z8DYVMI+XjVfQExb2okLPKtjg==", + "dependencies": { + "class-transformer": "^0.4.0", + "fabric-shim-api": "2.4.1", + "fast-safe-stringify": "^2.1.1", + "get-params": "^0.1.2", + "reflect-metadata": "^0.1.13", + "winston": "^3.3.3" + }, + "engines": { + "node": "^16.4.0", + "npm": "^8.0.0" + } + }, + "node_modules/fabric-shim": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.4.1.tgz", + "integrity": "sha512-9OE3qenXVX4kxk8yxyDC3g76RLBOEacSAE/QGldnDiS9c0ocgNQOMILLsiCjdk+sI5H6tjyOKbL/maTlEHMycg==", + "dependencies": { + "@fidm/x509": "^1.2.1", + "@grpc/grpc-js": "^1.4.1", + "@grpc/proto-loader": "^0.6.6", + "@types/node": "^16.11.1", + "ajv": "^6.12.2", + "fabric-contract-api": "2.4.1", + "fabric-shim-api": "2.4.1", + "fs-extra": "^10.0.0", + "reflect-metadata": "^0.1.13", + "winston": "^3.3.3", + "yargs": "^17.2.1", + "yargs-parser": "^20.2.9" + }, + "bin": { + "fabric-chaincode-node": "cli.js" + }, + "engines": { + "node": "^16.4.0", + "npm": "^8.0.0" + } + }, + "node_modules/fabric-shim-api": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.4.1.tgz", + "integrity": "sha512-jsCeI09omvRDI1Pv37ygyJdd5u+Okcf9WUxXh19vTa7APOA7/x2myKYZXrBi5ZDtroqabFcvRcszHZduN7m3ow==", + "engines": { + "eslint": "^6.6.0", + "node": "^16.4.0", + "npm": "^8.0.0" + } + }, + "node_modules/fabric-shim/node_modules/@types/node": { + "version": "16.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", + "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, + "node_modules/fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/foreground-child": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "dependencies": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, + "node_modules/fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-params": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", + "integrity": "sha1-uuDfq6WIoMYNeDTA2Nwv9g7u8v4=" + }, + "node_modules/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "dependencies": { + "is-stream": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "dependencies": { + "append-transform": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-deterministic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-deterministic/-/json-stringify-deterministic-1.0.1.tgz", + "integrity": "sha512-9Fg0OY3uyzozpvJ8TVbUk09PjzhT7O2Q5kEe30g6OrKhbA/Is92igcx0XDDX7E3yAwnIlUcYLRl+ZkVrBYVP7A==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "node_modules/logform": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", + "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "dependencies": { + "colors": "^1.2.1", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge-source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "dependencies": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "node_modules/nise": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "dev": true, + "dependencies": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nyc": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", + "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "caching-transform": "^3.0.2", + "convert-source-map": "^1.6.0", + "cp-file": "^6.2.0", + "find-cache-dir": "^2.1.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "merge-source-map": "^1.1.0", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", + "spawn-wrap": "^1.4.2", + "test-exclude": "^5.2.3", + "uuid": "^3.3.2", + "yargs": "^13.2.2", + "yargs-parser": "^13.0.0" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/nyc/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nyc/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/nyc/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", + "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/protobufjs/node_modules/@types/node": { + "version": "16.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", + "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "dev": true + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/sinon": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.3", + "diff": "^3.5.0", + "lolex": "^4.2.0", + "nise": "^1.5.2", + "supports-color": "^5.5.0" + } + }, + "node_modules/sinon-chai": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", + "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "dev": true, + "peerDependencies": { + "chai": "^4.0.0", + "sinon": ">=4.0.0" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sort-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", + "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", + "dependencies": { + "is-plain-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sort-keys-recursive": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sort-keys-recursive/-/sort-keys-recursive-2.1.2.tgz", + "integrity": "sha512-Qanszq4syO+XP88R/ctxvxabGOMj8kmPtjprYJmXhKmtXbWWZ4s7ZgxUXXFaA0I3waCA3F9WcQARZ5gjaRrh6w==", + "dependencies": { + "kind-of": "~6.0.2", + "sort-keys": "~4.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-wrap": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", + "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", + "dev": true, + "dependencies": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "dependencies": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-node/node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" + } + }, + "node_modules/tslint/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "dependencies": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "dependencies": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/winston-transport/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/winston/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "node_modules/yargs": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.0.tgz", + "integrity": "sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true, + "engines": { + "node": ">=4" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", + "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.0" + } + }, + "@babel/generator": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz", + "integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", + "integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.16.0", + "@babel/template": "^7.16.0", + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz", + "integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz", + "integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz", + "integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", + "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.15.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.4.tgz", + "integrity": "sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==", + "dev": true + }, + "@babel/template": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz", + "integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.0", + "@babel/parser": "^7.16.0", + "@babel/types": "^7.16.0" + } + }, + "@babel/traverse": { + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz", + "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.0", + "@babel/generator": "^7.16.0", + "@babel/helper-function-name": "^7.16.0", + "@babel/helper-hoist-variables": "^7.16.0", + "@babel/helper-split-export-declaration": "^7.16.0", + "@babel/parser": "^7.16.3", + "@babel/types": "^7.16.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", + "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.15.7", + "to-fast-properties": "^2.0.0" + } + }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@fidm/asn1": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", + "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==" + }, + "@fidm/x509": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", + "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", + "requires": { + "@fidm/asn1": "^1.0.4", + "tweetnacl": "^1.0.1" + } + }, + "@grpc/grpc-js": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.4.4.tgz", + "integrity": "sha512-a6222b7Dl6fIlMgzVl7e+NiRoLiZFbpcwvBH2Oli56Bn7W4/3Ld+86hK4ffPn5rx2DlDidmIcvIJiOQXyhv9gA==", + "requires": { + "@grpc/proto-loader": "^0.6.4", + "@types/node": ">=12.12.47" + }, + "dependencies": { + "@types/node": { + "version": "16.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", + "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==" + } + } + }, + "@grpc/proto-loader": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.7.tgz", + "integrity": "sha512-QzTPIyJxU0u+r2qGe8VMl3j/W2ryhEvBv7hc42OjYfthSj370fUrb7na65rG6w3YLZS/fb8p89iTBobfWGDgdw==", + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.1.1" + }, + "dependencies": { + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@types/chai": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", + "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", + "dev": true + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "@types/sinon": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-5.0.7.tgz", + "integrity": "sha512-opwMHufhUwkn/UUDk35LDbKJpA2VBsZT8WLU8NjayvRLGPxQkN+8XmfC2Xl35MAscBE8469koLLBjaI3XLEIww==", + "dev": true + }, + "@types/sinon-chai": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.6.tgz", + "integrity": "sha512-Z57LprQ+yOQNu9d6mWdHNvnmncPXzDWGSeLj+8L075/QahToapC4Q13zAFRVKV4clyBmdJ5gz4xBfVkOso5lXw==", + "dev": true, + "requires": { + "@types/chai": "*", + "@types/sinon": "*" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "async": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "requires": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "class-transformer": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", + "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cp-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", + "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^2.0.0", + "nested-error-stacks": "^2.0.0", + "pify": "^4.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "fabric-contract-api": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.4.1.tgz", + "integrity": "sha512-gFnr3beEnqOdzWEtkcf5O5hkVPWQHURA+Uunr9eZzfV+s5sgpewiIH/VhO8a9Z8DYVMI+XjVfQExb2okLPKtjg==", + "requires": { + "class-transformer": "^0.4.0", + "fabric-shim-api": "2.4.1", + "fast-safe-stringify": "^2.1.1", + "get-params": "^0.1.2", + "reflect-metadata": "^0.1.13", + "winston": "^3.3.3" + } + }, + "fabric-shim": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.4.1.tgz", + "integrity": "sha512-9OE3qenXVX4kxk8yxyDC3g76RLBOEacSAE/QGldnDiS9c0ocgNQOMILLsiCjdk+sI5H6tjyOKbL/maTlEHMycg==", + "requires": { + "@fidm/x509": "^1.2.1", + "@grpc/grpc-js": "^1.4.1", + "@grpc/proto-loader": "^0.6.6", + "@types/node": "^16.11.1", + "ajv": "^6.12.2", + "fabric-contract-api": "2.4.1", + "fabric-shim-api": "2.4.1", + "fs-extra": "^10.0.0", + "reflect-metadata": "^0.1.13", + "winston": "^3.3.3", + "yargs": "^17.2.1", + "yargs-parser": "^20.2.9" + }, + "dependencies": { + "@types/node": { + "version": "16.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", + "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==" + } + } + }, + "fabric-shim-api": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.4.1.tgz", + "integrity": "sha512-jsCeI09omvRDI1Pv37ygyJdd5u+Okcf9WUxXh19vTa7APOA7/x2myKYZXrBi5ZDtroqabFcvRcszHZduN7m3ow==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "foreground-child": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, + "fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-params": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", + "integrity": "sha1-uuDfq6WIoMYNeDTA2Nwv9g7u8v4=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "requires": { + "is-stream": "^1.0.1" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-deterministic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-deterministic/-/json-stringify-deterministic-1.0.1.tgz", + "integrity": "sha512-9Fg0OY3uyzozpvJ8TVbUk09PjzhT7O2Q5kEe30g6OrKhbA/Is92igcx0XDDX7E3yAwnIlUcYLRl+ZkVrBYVP7A==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "logform": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", + "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "requires": { + "colors": "^1.2.1", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "nise": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + } + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "nyc": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", + "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "caching-transform": "^3.0.2", + "convert-source-map": "^1.6.0", + "cp-file": "^6.2.0", + "find-cache-dir": "^2.1.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "merge-source-map": "^1.1.0", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", + "spawn-wrap": "^1.4.2", + "test-exclude": "^5.2.3", + "uuid": "^3.3.2", + "yargs": "^13.2.2", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", + "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "16.11.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", + "integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==" + } + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "sinon": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.3", + "diff": "^3.5.0", + "lolex": "^4.2.0", + "nise": "^1.5.2", + "supports-color": "^5.5.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "sinon-chai": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", + "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "dev": true, + "requires": {} + }, + "sort-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", + "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", + "requires": { + "is-plain-obj": "^2.0.0" + } + }, + "sort-keys-recursive": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sort-keys-recursive/-/sort-keys-recursive-2.1.2.tgz", + "integrity": "sha512-Qanszq4syO+XP88R/ctxvxabGOMj8kmPtjprYJmXhKmtXbWWZ4s7ZgxUXXFaA0I3waCA3F9WcQARZ5gjaRrh6w==", + "requires": { + "kind-of": "~6.0.2", + "sort-keys": "~4.2.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "spawn-wrap": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", + "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "dependencies": { + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + } + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + } + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.0.tgz", + "integrity": "sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "dependencies": { + "yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==" + } + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + } + } +} diff --git a/asset-transfer-basic/chaincode-typescript/package.json b/asset-transfer-basic/chaincode-typescript/package.json index 66f41315..1cc159d9 100644 --- a/asset-transfer-basic/chaincode-typescript/package.json +++ b/asset-transfer-basic/chaincode-typescript/package.json @@ -12,18 +12,23 @@ "lint": "tslint -c tslint.json 'src/**/*.ts'", "pretest": "npm run lint", "test": "nyc mocha -r ts-node/register src/**/*.spec.ts", - "start": "fabric-chaincode-node start", + "start": "set -x && fabric-chaincode-node start", "build": "tsc", "build:watch": "tsc -w", - "prepublishOnly": "npm run build" + "prepublishOnly": "npm run build", + "docker": "docker build -f ./Dockerfile -t asset-transfer-basic .", + "package": "npm run build && npm shrinkwrap", + "start:server-nontls": "set -x && fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID", + "start:server-debug": "set -x && NODE_OPTIONS='--inspect=0.0.0.0:9229' fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID", + "start:server": "set -x && fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID --chaincode-tls-key-file=/hyperledger/privatekey.pem --chaincode-tls-client-cacert-file=/hyperledger/rootcert.pem --chaincode-tls-cert-file=/hyperledger/cert.pem" }, "engineStrict": true, "author": "Hyperledger", "license": "Apache-2.0", "dependencies": { - "fabric-contract-api": "^2.0.0", - "fabric-shim": "^2.0.0", - "json-stringify-deterministic": "^1.0.0", + "fabric-contract-api": "^2.4.0", + "fabric-shim": "^2.4.0", + "json-stringify-deterministic": "^1.0.1", "sort-keys-recursive": "^2.1.2" }, "devDependencies": { diff --git a/test-network/CHAINCODE_AS_A_SERVICE_TUTORIAL.md b/test-network/CHAINCODE_AS_A_SERVICE_TUTORIAL.md new file mode 100644 index 00000000..a0788b18 --- /dev/null +++ b/test-network/CHAINCODE_AS_A_SERVICE_TUTORIAL.md @@ -0,0 +1,204 @@ +# Running Chaincode as Service with the Test Network + +The chaincode-as-a-service feature is a very useful and practical way to run 'Smart Contracts'. Traditionally the Fabric Peer has taken on the role of orchestrating the complete lifecycle of the chaincode. It required access to the Docker Daemon to create images, and start containers. Java, NodeJS and Go chaincode frameworks were explicitly known to the peer including how they should be built and started. + +As a result this makes it very hard to deploy into Kubernetes (K8S) style environments, or to run in any form of debug mode. Additionally, the code is being rebuilt by the peer therefore there is some degree of uncertainty about what dependencies have been pulled in. + +Chaincode-as-service requires you to orchestrate the build and deployment phase yourself. Whilst this is an additional step, it gives control back. The Peer still requires a 'chaincode package' to be installed. In this case this doesn't contain code, but the information about where the chaincode is hosted. (Hostname,Port,TLS config etc) + +## Fabric v2.4.1 Improvements + +We need to use the latest 2.4.1 release as this contains some improvements to make this process easier. The core functionality is available in earlier releases but requires more configuration. + +- The docker image for the peer contains a builder for chaincode-as-a-service preconfigured. This is named 'ccaasbuilder'. This removes the need to build your own external builder and repackage and configure the peer +- The `ccaasbuilder` applications are included in the binary tgz archive download for use in other circumstances. The `sampleconfig/core.yaml` is updated as well to refer to 'ccaasbuilder' +- The 2.4.1 Java Chaincode release has been updated to remove the need to write a custom bootstrap main class, similar to the NodeJS Chaincode. It is intended that this will be added to the go chaincode as well. + +## End-to-end with the the test-network + +The `test-network` and some of the chaincodes have been updated to support running chaincode-as-a-service. The commands below assume that you've got the latest fabric-samples cloned, along with the latest Fabric docker images. + +It's useful to have two terminal windows open, one for starting the Fabric Network, and a second for monitoring all the docker containers. + +In your 'monitoring' window, run this to watch all activity from the all the docker containers on the `fabric_test` network; this will monitor all the docker containers that are added to the `fabric-test` network. The network is usually created by the `./network.sh up` command, so remember to delay running this until at lest the network is created. It is possible to precreate the network with `docker network create fabric-test` if you wish. + +```bash +# from the fabric-samples repo +./test-network/monitordocker.sh +``` + + +In the 'Fabric Network' window, start the test network + +```bash +cd test-network +./network.sh up createChannel +``` + +You can run other variants of this command, eg to use CouchDB or CAs, without affecting the '-as-a-service' feature. The three keys steps are: + +- Build a docker image of the contract. Both `/asset-transfer-basic/chaincode-typescript` and `/asset-transfer-basic/chaincode-java` have been updated with Dockerfiles +- Install, Approve and Commit a chaincode definition. This is unchanged, but the chaincode package contains connection information (hostname,port,tls certificates etc.), not code +- Start the docker container(s) containing the contract + +Note that the order listed isn't mandatory. The key thing is that the containers are running before the first transaction is set by the peer. Remember that this could be on the `commit` if the `initRequired` flag is set. + +This sequence can be run as follows +```bash +./network.sh deployCCAAS -ccn basicts -ccp ../asset-transfer-basic/chaincode-typescript +``` + +This is very similar to the `deployCC` command, it needs the name, and path. But also needs to have the port the chaincode container is going use. As each container is on the `fabric-test` network, you might wish to alter this so there are no collisions with other chaincode containers. + +You should be able to see the contract starting in the monitoring window. There will be two containers running, one for org1 and one for org2. The container names contain the organzation/peer and the name of the chaincode. + +To test things are working you can invoke the 'Contract Metadata' function. For information on how to work as different organizations see [Interacting with the network](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html#interacting-with-the-network) + +```bash +# Environment variables for Org1 + +export CORE_PEER_TLS_ENABLED=true +export CORE_PEER_LOCALMSPID="Org1MSP" +export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt +export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp +export CORE_PEER_ADDRESS=localhost:7051 + +# invoke the function +peer chaincode query -C mychannel -n basicts -c '{"Args":["org.hyperledger.fabric:GetMetadata"]}' | jq +``` + +If you don't have `jq` installed omit ` | jq`. The metadata shows the details of the deployed contract and is JSON, so jq makes it easier to read. You can repeat the above commands for org2 to confirm that is working. + +To run the Java example, change the `deployCCAAS` command as follows, This will create a two new containers. + +```bash +./network.sh deployCCAAS -ccn basicj -ccp ../asset-transfer-basic/chaincode-typescript +``` + + +### Troubleshooting + +If the JSON structure passed in is badly formatted JSON this error will be in the peer log + +``` +::Error: Failed to unmarshal json: cannot unmarshal string into Go value of type map[string]interface {} command=build +``` + +## How to configure each langauge + +Each language can work in the '-as-a-service' mode. Note that the approaches here are based on the very latest libraries. +When starting the image you can also specify any of the TLS options or additional logging options for the respective chaincode libraries. + +### Java + +With the v2.4.1 Java Chaincode libraries, there are no code changes to make or build changes. The '-as-a-service' mode will be used if the environment variable `CHAINCODE_SERVER_ADDRESS` is set. + +A sample docker run command could be as follows. The two key variables that are needed are the `CHAINCODE_SERVER_ADDRESS` and `CORE_CHAICODE_ID_NAME` + +``` + docker run --rm -d --name peer0org1_assettx_ccaas \ + --network fabric_test \ + -e CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999 \ + -e CORE_CHAINCODE_ID_NAME= \ + assettx_ccaas_image:latest +``` + +### Nodejs + +For NodeJS (JavaScript or TypeScript) chaincode, typically the `package.json` has `fabric-chaincode-node start` as the main start command. To run in the '-as-a-service' mode change this to `fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID` + +### Golang + +TBC + +## Debugging the Chaincode + +Running in the '-as-a-service' mode offers options, similar to how the Fabric 'dev' mode works on debugging code. The restrictions of the 'dev' mode don't apply. + +There is an option `-ccaasdr false` that can be provided on the `deployCCAAS` command. This will _not_ build the docker image or start a docker container. It does output the commands it would have run. + +Run this command, and you'll see similar output +``` +./network.sh deployCCAAS -ccn basicj -ccp ../asset-transfer-basic/chaincode-java -ccaasdr false +#.... +Not building docker image; this the command we would have run +docker build -f ../asset-transfer-basic/chaincode-java/Dockerfile -t basicj_ccaas_image:latest --build-arg CC_SERVER_PORT=9999 ../asset-transfer-basic/chaincode-java +#.... +Not starting docker containers; these are the commands we would have run + docker run --rm -d --name peer0org1_basicj_ccaas --network fabric_test -e CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999 -e CHAINCODE_ID=basicj_1.0:59dcd73a14e2db8eab7f7683343ce27ac242b93b4e8075605a460d63a0438405 -e CORE_CHAINCODE_ID_NAME=basicj_1.0:59dcd73a14e2db8eab7f7683343ce27ac242b93b4e8075605a460d63a0438405 basicj_ccaas_image:latest +``` + +Depending on your directory, and what you need to debug you might need to adjust these commands. + +### Building the docker image +The first thing needed is to build the docker image. Remember that so long as the peer can connect to the hostname:port given in the `connection.json` the actual packaging of the chaincode is not important to the peer. You are at liberty to adjust the dockerfiles given hgere. + +To manually build the docker image for the `asset-transfer-basic/chaincode-java` + +``` +docker build -f ../asset-transfer-basic/chaincode-java/Dockerfile -t basicj_ccaas_image:latest --build-arg CC_SERVER_PORT=9999 ../asset-transfer-basic/chaincode-java +``` + +### Starting the docker container + +You need to start the docker container. + +NodeJs for example, could be started like this +``` + docker run --rm -it -p 9229:9229 --name peer0org2_basic_ccaas --network fabric_test -e DEBUG=true -e CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999 -e CHAINCODE_ID=basic_1.0:7c7dff5cdc43c77ccea028c422b3348c3c1fb5a26ace0077cf3cc627bd355ef0 -e CORE_CHAINCODE_ID_NAME=basic_1.0:7c7dff5cdc43c77ccea028c422b3348c3c1fb5a26ace0077cf3cc627bd355ef0 basic_ccaas_image:latest +``` + +Java for example, could be started like this + +``` + docker run --rm -it --name peer0org1_basicj_ccaas -p 8000:8000 --network fabric_test -e DEBUG=true -e CHAINCODE_SERVER_ADDRESS=0.0.0.0:9999 -e CHAINCODE_ID=basicj_1.0:b014a03d8eb1898535e25b4dfeeb3f8244c9f07d91a06aec03e2d19174c45e4f -e CORE_CHAINCODE_ID_NAME=basicj_1.0:b014a03d8e +b1898535e25b4dfeeb3f8244c9f07d91a06aec03e2d19174c45e4f basicj_ccaas_image:latest +``` + +For all languages please note: + +- the name of the container needs to match what the peer has in the `connection.json` +- the peer is connecting to the chaincode container via the docker network. Therefore port 9999 does not need to forwarded to the host +- If you are going to single step in a debugger, then you are likely to hit the Fabric transaction timeout value. By default this is 30seconds, meaning the chaincode has to complete transactions in 30 seconds or less. In the `test-network/docker/docker-composer-test-net.yml` add `CORE_CHAINCODE_EXECUTETIMEOUT=300s` to the environment options of each peer. +- In the command above, the `-d` option has been removed from the command the test-network would have used, and has been replaced with `-it`. This means that docker container will not run in detached mode, and will run in the foregroud. + +For Node.js please note: + +- Port 9229 is forwarded however - this is the debug port used by NodeJS +- `-e DEBUG=true` will trigger the node runtime to be started in debug mode. This is encoded in the `docker/docker-entrypoint.sh` script - this is an example and you may wish to remove this in production images for security +- If you are using typescript, ensure that the typescript has been compiled with sourcemaps, otherwise a debugger will struggle matching up the source code. + +For Java please note: +- Port 800 is forwarded, the debug port for the JVM +- `-e DEBUG=true` will trigger the node runtime to be started in debug mode. This is encoded in the `docker/docker-entrypoint.sh` script - this is an example and you may wish to remove this in production images for security +- In the java command with the option to start the debugger is `java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 -jar /chaincode.jar` Note the `0.0.0.0` as the debug port needs to be bound to all network adapters so the debugger can be attached from outside the container + + +## Running with multiple peers + +In the traditional approach, each peer that the chaincode is approved on will have a container running the chaincode. With the '-as-a-service' approach we need to achieve the same architecture. + +As the `connection.json` contains the address of the running chaincode container, it can be updated to ensure that each peer connects to a different container. However the as the `connection.json` in the chaincode package, Fabric mandates that the package id is consistent amongst all peers in an organization. To achieve that +the the external builder supports a template capability. The context from this template is taken from an environment variable set on each Peer. `CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG` + +We can define the address to be a template in the `connection.json` + +```json +{ + "address": "{{.peername}}_assettransfer_ccaas:9999", + "dial_timeout": "10s", + "tls_required": false +} +``` + +In the peer's environment configuration we then set for org1's peer1 + +``` +CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG="{\"peername\":\"org1peer1\"}" +``` + +The external builder will then resolve this address to be `org1peer1_assettransfer_ccaas:9999` for the peer to use. + +Each peer can have there own separate configuration, and therefore different addresses. The JSON string that is set can have any structure, so long as the templates (in golang template syntax) match. + +Any value in the `connection.json` can be templated - but only the values and not the keys. \ No newline at end of file diff --git a/test-network/README.md b/test-network/README.md index f861db94..d982d51e 100644 --- a/test-network/README.md +++ b/test-network/README.md @@ -20,5 +20,11 @@ You can then set up the environment variables for each organization. The `./setO export $(./setOrgEnv.sh Org2 | xargs) ``` +(Note bash v4 is required for the scripts) + You will now be able to run the `peer` commands in the context of Org2. If a different command prompt you can run the same command with Org1 instead. -The `setOrgEnv` script outputs a series of `=` strings. These can then be fed into the export command for your current shell \ No newline at end of file +The `setOrgEnv` script outputs a series of `=` strings. These can then be fed into the export command for your current shell + +## Chaincode-as-a-service + +To learn more about how to use the improvements to the Chaincode-as-a-service please see this [tutorial](./test-network/../CHAINCODE_AS_A_SERVICE_TUTORIAL.md). It is expected that this will move to augment the tutorial in the [Hyperledger Fabric ReadTheDocs](https://hyperledger-fabric.readthedocs.io/en/release-2.4/cc_service.html) \ No newline at end of file diff --git a/test-network/docker/docker-compose-test-net.yaml b/test-network/docker/docker-compose-test-net.yaml index 87f68318..059f5838 100644 --- a/test-network/docker/docker-compose-test-net.yaml +++ b/test-network/docker/docker-compose-test-net.yaml @@ -86,6 +86,8 @@ services: - CORE_PEER_LOCALMSPID=Org1MSP - CORE_OPERATIONS_LISTENADDRESS=peer0.org1.example.com:9444 - CORE_METRICS_PROVIDER=prometheus + - CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG={"peername":"peer0org1"} + - CORE_CHAINCODE_EXECUTETIMEOUT=300s volumes: - ${DOCKER_SOCK}:/host/var/run/docker.sock - ../organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp @@ -126,6 +128,8 @@ services: - CORE_PEER_LOCALMSPID=Org2MSP - CORE_OPERATIONS_LISTENADDRESS=peer0.org2.example.com:9445 - CORE_METRICS_PROVIDER=prometheus + - CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG={"peername":"peer0org2"} + - CORE_CHAINCODE_EXECUTETIMEOUT=300s volumes: - ${DOCKER_SOCK}:/host/var/run/docker.sock - ../organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp diff --git a/test-network/monitordocker.sh b/test-network/monitordocker.sh new file mode 100755 index 00000000..c32986c8 --- /dev/null +++ b/test-network/monitordocker.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# This script uses the logspout and http stream tools to let you watch the docker containers +# in action. +# +# More information at https://github.com/gliderlabs/logspout/tree/master/httpstream + +if [ -z "$1" ]; then + DOCKER_NETWORK=fabric_test +else + DOCKER_NETWORK="$1" +fi + +if [ -z "$2" ]; then + PORT=8000 +else + PORT="$2" +fi + +echo Starting monitoring on all containers on the network ${DOCKER_NETWORK} + +docker kill logspout 2> /dev/null 1>&2 || true +docker rm logspout 2> /dev/null 1>&2 || true + +trap "docker kill logspout" SIGINT + +docker run -d --rm --name="logspout" \ + --volume=/var/run/docker.sock:/var/run/docker.sock \ + --publish=127.0.0.1:${PORT}:80 \ + --network ${DOCKER_NETWORK} \ + gliderlabs/logspout +sleep 3 +curl http://127.0.0.1:${PORT}/logs diff --git a/test-network/network.sh b/test-network/network.sh index 17c91ff3..90ace0db 100755 --- a/test-network/network.sh +++ b/test-network/network.sh @@ -274,6 +274,14 @@ function deployCC() { fi } +## Call the script to deploy a chaincode to the channel +function deployCCAAS() { + scripts/deployCCAAS.sh $CHANNEL_NAME $CC_NAME $CC_SRC_PATH $CCAAS_DOCKER_RUN $CC_VERSION $CC_SEQUENCE $CC_INIT_FCN $CC_END_POLICY $CC_COLL_CONFIG $CLI_DELAY $MAX_RETRY $VERBOSE $CCAAS_DOCKER_RUN + + if [ $? -ne 0 ]; then + fatalln "Deploying chaincode-as-a-service failed" + fi +} # Tear down running network function networkDown() { @@ -283,10 +291,13 @@ function networkDown() { # Don't remove the generated artifacts -- note, the ledgers are always removed if [ "$MODE" != "restart" ]; then # Bring down the network, deleting the volumes + docker volume rm docker_orderer.example.com docker_peer0.org1.example.com docker_peer0.org2.example.com #Cleanup the chaincode containers clearContainers #Cleanup images removeUnwantedImages + # + docker kill $(docker ps -q --filter name=ccaas) || true # remove orderer block and other channel configuration transactions and certs docker run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf system-genesis-block/*.block organizations/peerOrganizations organizations/ordererOrganizations' ## remove fabric ca artifacts @@ -331,6 +342,8 @@ COMPOSE_FILE_ORG3=addOrg3/docker/docker-compose-org3.yaml # # chaincode language defaults to "NA" CC_SRC_LANGUAGE="NA" +# default to running the docker commands for the CCAAS +CCAAS_DOCKER_RUN=true # Chaincode version CC_VERSION="1.0" # Chaincode definition sequence @@ -422,6 +435,10 @@ while [[ $# -ge 1 ]] ; do CC_INIT_FCN="$2" shift ;; + -ccaasdocker ) + CCAAS_DOCKER_RUN="$2" + shift + ;; -verbose ) VERBOSE=true shift @@ -445,29 +462,26 @@ fi # Determine mode of operation and printing out what we asked for if [ "$MODE" == "up" ]; then infoln "Starting nodes with CLI timeout of '${MAX_RETRY}' tries and CLI delay of '${CLI_DELAY}' seconds and using database '${DATABASE}' ${CRYPTO_MODE}" + networkUp elif [ "$MODE" == "createChannel" ]; then infoln "Creating channel '${CHANNEL_NAME}'." infoln "If network is not up, starting nodes with CLI timeout of '${MAX_RETRY}' tries and CLI delay of '${CLI_DELAY}' seconds and using database '${DATABASE} ${CRYPTO_MODE}" + createChannel elif [ "$MODE" == "down" ]; then infoln "Stopping network" + networkDown elif [ "$MODE" == "restart" ]; then infoln "Restarting network" + networkDown + networkUp elif [ "$MODE" == "deployCC" ]; then infoln "deploying chaincode on channel '${CHANNEL_NAME}'" + deployCC +elif [ "$MODE" == "deployCCAAS" ]; then + infoln "deploying chaincode-as-a-service on channel '${CHANNEL_NAME}'" + deployCCAAS else printHelp exit 1 fi -if [ "${MODE}" == "up" ]; then - networkUp -elif [ "${MODE}" == "createChannel" ]; then - createChannel -elif [ "${MODE}" == "deployCC" ]; then - deployCC -elif [ "${MODE}" == "down" ]; then - networkDown -else - printHelp - exit 1 -fi diff --git a/test-network/scripts/ccutils.sh b/test-network/scripts/ccutils.sh new file mode 100644 index 00000000..26a1120e --- /dev/null +++ b/test-network/scripts/ccutils.sh @@ -0,0 +1,165 @@ +#!/bin/bash + + +# installChaincode PEER ORG +function installChaincode() { + ORG=$1 + setGlobals $ORG + set -x + peer lifecycle chaincode install ${CC_NAME}.tar.gz >&log.txt + res=$? + { set +x; } 2>/dev/null + cat log.txt + verifyResult $res "Chaincode installation on peer0.org${ORG} has failed" + successln "Chaincode is installed on peer0.org${ORG}" +} + +# queryInstalled PEER ORG +function queryInstalled() { + ORG=$1 + setGlobals $ORG + set -x + peer lifecycle chaincode queryinstalled >&log.txt + res=$? + { set +x; } 2>/dev/null + cat log.txt + PACKAGE_ID=$(sed -n "/${CC_NAME}_${CC_VERSION}/{s/^Package ID: //; s/, Label:.*$//; p;}" log.txt) + verifyResult $res "Query installed on peer0.org${ORG} has failed" + successln "Query installed successful on peer0.org${ORG} on channel" +} + +# approveForMyOrg VERSION PEER ORG +function approveForMyOrg() { + ORG=$1 + setGlobals $ORG + set -x + peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --package-id ${PACKAGE_ID} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt + res=$? + { set +x; } 2>/dev/null + cat log.txt + verifyResult $res "Chaincode definition approved on peer0.org${ORG} on channel '$CHANNEL_NAME' failed" + successln "Chaincode definition approved on peer0.org${ORG} on channel '$CHANNEL_NAME'" +} + +# checkCommitReadiness VERSION PEER ORG +function checkCommitReadiness() { + ORG=$1 + shift 1 + setGlobals $ORG + infoln "Checking the commit readiness of the chaincode definition 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 check the commit readiness of the chaincode definition on peer0.org${ORG}, Retry after $DELAY seconds." + set -x + peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} --output json >&log.txt + res=$? + { set +x; } 2>/dev/null + let rc=0 + for var in "$@"; do + grep "$var" log.txt &>/dev/null || let rc=1 + done + COUNTER=$(expr $COUNTER + 1) + done + cat log.txt + if test $rc -eq 0; then + infoln "Checking the commit readiness of the chaincode definition successful on peer0.org${ORG} on channel '$CHANNEL_NAME'" + else + fatalln "After $MAX_RETRY attempts, Check commit readiness result on peer0.org${ORG} is INVALID!" + fi +} + +# commitChaincodeDefinition VERSION PEER ORG (PEER ORG)... +function commitChaincodeDefinition() { + parsePeerConnectionParameters $@ + res=$? + verifyResult $res "Invoke transaction failed on channel '$CHANNEL_NAME' due to uneven number of peer and org parameters " + + # 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 localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" --channelID $CHANNEL_NAME --name ${CC_NAME} "${PEER_CONN_PARMS[@]}" --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt + res=$? + { set +x; } 2>/dev/null + cat 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() { + ORG=$1 + setGlobals $ORG + EXPECTED_RESULT="Version: ${CC_VERSION}, Sequence: ${CC_SEQUENCE}, Endorsement Plugin: escc, Validation Plugin: vscc" + infoln "Querying chaincode definition 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 committed status on peer0.org${ORG}, Retry after $DELAY seconds." + set -x + peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name ${CC_NAME} >&log.txt + res=$? + { set +x; } 2>/dev/null + test $res -eq 0 && VALUE=$(cat 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 log.txt + if test $rc -eq 0; then + successln "Query chaincode definition successful on peer0.org${ORG} on channel '$CHANNEL_NAME'" + else + fatalln "After $MAX_RETRY attempts, Query chaincode definition result on peer0.org${ORG} 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 " + + # 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 + fcn_call='{"function":"'${CC_INIT_FCN}'","Args":[]}' + 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} >&log.txt + res=$? + { set +x; } 2>/dev/null + cat 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"]}' >&log.txt + res=$? + { set +x; } 2>/dev/null + let rc=$res + COUNTER=$(expr $COUNTER + 1) + done + cat 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/test-network/scripts/deployCC.sh b/test-network/scripts/deployCC.sh index 951aae5a..58d82d54 100755 --- a/test-network/scripts/deployCC.sh +++ b/test-network/scripts/deployCC.sh @@ -109,6 +109,7 @@ fi # import utils . scripts/envVar.sh +. scripts/ccutils.sh packageChaincode() { set -x @@ -120,169 +121,6 @@ packageChaincode() { successln "Chaincode is packaged" } -# installChaincode PEER ORG -installChaincode() { - ORG=$1 - setGlobals $ORG - set -x - peer lifecycle chaincode install ${CC_NAME}.tar.gz >&log.txt - res=$? - { set +x; } 2>/dev/null - cat log.txt - verifyResult $res "Chaincode installation on peer0.org${ORG} has failed" - successln "Chaincode is installed on peer0.org${ORG}" -} - -# queryInstalled PEER ORG -queryInstalled() { - ORG=$1 - setGlobals $ORG - set -x - peer lifecycle chaincode queryinstalled >&log.txt - res=$? - { set +x; } 2>/dev/null - cat log.txt - PACKAGE_ID=$(sed -n "/${CC_NAME}_${CC_VERSION}/{s/^Package ID: //; s/, Label:.*$//; p;}" log.txt) - verifyResult $res "Query installed on peer0.org${ORG} has failed" - successln "Query installed successful on peer0.org${ORG} on channel" -} - -# approveForMyOrg VERSION PEER ORG -approveForMyOrg() { - ORG=$1 - setGlobals $ORG - set -x - peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --package-id ${PACKAGE_ID} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt - res=$? - { set +x; } 2>/dev/null - cat log.txt - verifyResult $res "Chaincode definition approved on peer0.org${ORG} on channel '$CHANNEL_NAME' failed" - successln "Chaincode definition approved on peer0.org${ORG} on channel '$CHANNEL_NAME'" -} - -# checkCommitReadiness VERSION PEER ORG -checkCommitReadiness() { - ORG=$1 - shift 1 - setGlobals $ORG - infoln "Checking the commit readiness of the chaincode definition 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 check the commit readiness of the chaincode definition on peer0.org${ORG}, Retry after $DELAY seconds." - set -x - peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} --output json >&log.txt - res=$? - { set +x; } 2>/dev/null - let rc=0 - for var in "$@"; do - grep "$var" log.txt &>/dev/null || let rc=1 - done - COUNTER=$(expr $COUNTER + 1) - done - cat log.txt - if test $rc -eq 0; then - infoln "Checking the commit readiness of the chaincode definition successful on peer0.org${ORG} on channel '$CHANNEL_NAME'" - else - fatalln "After $MAX_RETRY attempts, Check commit readiness result on peer0.org${ORG} is INVALID!" - fi -} - -# commitChaincodeDefinition VERSION PEER ORG (PEER ORG)... -commitChaincodeDefinition() { - parsePeerConnectionParameters $@ - res=$? - verifyResult $res "Invoke transaction failed on channel '$CHANNEL_NAME' due to uneven number of peer and org parameters " - - # 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 localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" --channelID $CHANNEL_NAME --name ${CC_NAME} "${PEER_CONN_PARMS[@]}" --version ${CC_VERSION} --sequence ${CC_SEQUENCE} ${INIT_REQUIRED} ${CC_END_POLICY} ${CC_COLL_CONFIG} >&log.txt - res=$? - { set +x; } 2>/dev/null - cat 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 -queryCommitted() { - ORG=$1 - setGlobals $ORG - EXPECTED_RESULT="Version: ${CC_VERSION}, Sequence: ${CC_SEQUENCE}, Endorsement Plugin: escc, Validation Plugin: vscc" - infoln "Querying chaincode definition 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 committed status on peer0.org${ORG}, Retry after $DELAY seconds." - set -x - peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name ${CC_NAME} >&log.txt - res=$? - { set +x; } 2>/dev/null - test $res -eq 0 && VALUE=$(cat 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 log.txt - if test $rc -eq 0; then - successln "Query chaincode definition successful on peer0.org${ORG} on channel '$CHANNEL_NAME'" - else - fatalln "After $MAX_RETRY attempts, Query chaincode definition result on peer0.org${ORG} is INVALID!" - fi -} - -chaincodeInvokeInit() { - parsePeerConnectionParameters $@ - res=$? - verifyResult $res "Invoke transaction failed on channel '$CHANNEL_NAME' due to uneven number of peer and org parameters " - - # 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 - fcn_call='{"function":"'${CC_INIT_FCN}'","Args":[]}' - 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} >&log.txt - res=$? - { set +x; } 2>/dev/null - cat log.txt - verifyResult $res "Invoke execution on $PEERS failed " - successln "Invoke transaction successful on $PEERS on channel '$CHANNEL_NAME'" -} - -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":["queryAllCars"]}' >&log.txt - res=$? - { set +x; } 2>/dev/null - let rc=$res - COUNTER=$(expr $COUNTER + 1) - done - cat 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 -} - ## package the chaincode packageChaincode diff --git a/test-network/scripts/deployCCAAS.sh b/test-network/scripts/deployCCAAS.sh new file mode 100755 index 00000000..4a8e1b3a --- /dev/null +++ b/test-network/scripts/deployCCAAS.sh @@ -0,0 +1,206 @@ +#!/bin/bash +# +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +source scripts/utils.sh + +CHANNEL_NAME=${1:-"mychannel"} +CC_NAME=${2} +CC_SRC_PATH=${3} +CCAAS_DOCKER_RUN=${4:-"true"} +CC_VERSION=${5:-"1.0"} +CC_SEQUENCE=${6:-"1"} +CC_INIT_FCN=${7:-"NA"} +CC_END_POLICY=${8:-"NA"} +CC_COLL_CONFIG=${9:-"NA"} +DELAY=${10:-"3"} +MAX_RETRY=${11:-"5"} +VERBOSE=${12:-"false"} + +CCAAS_SERVER_PORT=9999 + +println "executing with the following" +println "- CHANNEL_NAME: ${C_GREEN}${CHANNEL_NAME}${C_RESET}" +println "- CC_NAME: ${C_GREEN}${CC_NAME}${C_RESET}" +println "- CC_SRC_PATH: ${C_GREEN}${CC_SRC_PATH}${C_RESET}" +println "- CC_VERSION: ${C_GREEN}${CC_VERSION}${C_RESET}" +println "- CC_SEQUENCE: ${C_GREEN}${CC_SEQUENCE}${C_RESET}" +println "- CC_END_POLICY: ${C_GREEN}${CC_END_POLICY}${C_RESET}" +println "- CC_COLL_CONFIG: ${C_GREEN}${CC_COLL_CONFIG}${C_RESET}" +println "- CC_INIT_FCN: ${C_GREEN}${CC_INIT_FCN}${C_RESET}" +println "- CCAAS_DOCKER_RUN: ${C_GREEN}${CCAAS_DOCKER_RUN}${C_RESET}" +println "- DELAY: ${C_GREEN}${DELAY}${C_RESET}" +println "- MAX_RETRY: ${C_GREEN}${MAX_RETRY}${C_RESET}" +println "- VERBOSE: ${C_GREEN}${VERBOSE}${C_RESET}" + +FABRIC_CFG_PATH=$PWD/../config/ + +#User has not provided a name +if [ -z "$CC_NAME" ] || [ "$CC_NAME" = "NA" ]; then + fatalln "No chaincode name was provided. Valid call example: ./network.sh deployCCAS -ccn basic -ccp ../asset-transfer-basic/chaincode-go " + +# User has not provided a path +elif [ -z "$CC_SRC_PATH" ] || [ "$CC_SRC_PATH" = "NA" ]; then + fatalln "No chaincode path was provided. Valid call example: ./network.sh deployCCAS -ccn basic -ccp ../asset-transfer-basic/chaincode-go " + +## Make sure that the path to the chaincode exists +elif [ ! -d "$CC_SRC_PATH" ]; then + fatalln "Path to chaincode does not exist. Please provide different path." +fi + + + +if [ "$CC_END_POLICY" = "NA" ]; then + CC_END_POLICY="" +else + CC_END_POLICY="--signature-policy $CC_END_POLICY" +fi + +if [ "$CC_COLL_CONFIG" = "NA" ]; then + CC_COLL_CONFIG="" +else + CC_COLL_CONFIG="--collections-config $CC_COLL_CONFIG" +fi + +# import utils +. scripts/envVar.sh +. scripts/ccutils.sh + +packageChaincode() { + + address="{{.peername}}_${CC_NAME}_ccaas:${CCAAS_SERVER_PORT}" + prefix=$(basename "$0") + tempdir=$(mktemp -d -t "$prefix.XXXXXXXX") || error_exit "Error creating temporary directory" + label=${CC_NAME}_${CC_VERSION} + mkdir -p "$tempdir/src" + +cat > "$tempdir/src/connection.json" < "$tempdir/pkg/metadata.json" +{ + "type": "ccaas", + "label": "$label" +} +METADATA-EOF + + tar -C "$tempdir/src" -czf "$tempdir/pkg/code.tar.gz" . + tar -C "$tempdir/pkg" -czf "$CC_NAME.tar.gz" metadata.json code.tar.gz + rm -Rf "$tempdir" + + successln "Chaincode is packaged ${address}" + +} + +buildDockerImages() { + # if set don't build - useful when you want to debug yourself + if [ "$CCAAS_DOCKER_RUN" = "true" ]; then + # build the docker container + infoln "Building Chaincode-as-a-Service docker image '${CC_NAME}' '${CC_SRC_PATH}'" + set -x + docker build -f $CC_SRC_PATH/Dockerfile -t ${CC_NAME}_ccaas_image:latest --build-arg CC_SERVER_PORT=9999 $CC_SRC_PATH >&log.txt + res=$? + { set +x; } 2>/dev/null + cat log.txt + verifyResult $res "Docker buid of chaincode-as-a-service container failed" + successln "Docker image '${CC_NAME}_ccaas_image:latest' built succesfully" + else + infoln "Not building docker image; this the command we would have run" + infoln "docker build -f $CC_SRC_PATH/Dockerfile -t ${CC_NAME}_ccaas_image:latest --build-arg CC_SERVER_PORT=9999 $CC_SRC_PATH" + fi +} + +startDockerContainer() { + # start the docker container + if [ "$CCAAS_DOCKER_RUN" = "true" ]; then + infoln "Starting the Chaincode-as-a-Service docker container..." + set -x + docker run --rm -d --name peer0org1_${CC_NAME}_ccaas \ + --network fabric_test \ + -e CHAINCODE_SERVER_ADDRESS=0.0.0.0:${CCAAS_SERVER_PORT} \ + -e CHAINCODE_ID=$PACKAGE_ID -e CORE_CHAINCODE_ID_NAME=$PACKAGE_ID \ + ${CC_NAME}_ccaas_image:latest + + docker run --rm -d --name peer0org2_${CC_NAME}_ccaas \ + --network fabric_test \ + -e CHAINCODE_SERVER_ADDRESS=0.0.0.0:${CCAAS_SERVER_PORT} \ + -e CHAINCODE_ID=$PACKAGE_ID -e CORE_CHAINCODE_ID_NAME=$PACKAGE_ID \ + ${CC_NAME}_ccaas_image:latest + res=$? + { set +x; } 2>/dev/null + cat log.txt + verifyResult $res "Failed to start the container container '${CC_NAME}_ccaas_image:latest' " + successln "Docker container started succesfully '${CC_NAME}_ccaas_image:latest'" + else + + infoln "Not starting docker containers; these are the commands we would have run" + infoln " docker run --rm -d --name peer0org1_${CC_NAME}_ccaas \ + --network fabric_test \ + -e CHAINCODE_SERVER_ADDRESS=0.0.0.0:${CCAAS_SERVER_PORT} \ + -e CHAINCODE_ID=$PACKAGE_ID -e CORE_CHAINCODE_ID_NAME=$PACKAGE_ID \ + ${CC_NAME}_ccaas_image:latest" + + fi +} + +# Build the docker image +buildDockerImages + +## package the chaincode +packageChaincode + +## Install chaincode on peer0.org1 and peer0.org2 +infoln "Installing chaincode on peer0.org1..." +installChaincode 1 +infoln "Install chaincode on peer0.org2..." +installChaincode 2 + +## query whether the chaincode is installed +queryInstalled 1 + +## approve the definition for org1 +approveForMyOrg 1 + +## check whether the chaincode definition is ready to be committed +## expect org1 to have approved and org2 not to +checkCommitReadiness 1 "\"Org1MSP\": true" "\"Org2MSP\": false" +checkCommitReadiness 2 "\"Org1MSP\": true" "\"Org2MSP\": false" + +## now approve also for org2 +approveForMyOrg 2 + +## check whether the chaincode definition is ready to be committed +## expect them both to have approved +checkCommitReadiness 1 "\"Org1MSP\": true" "\"Org2MSP\": true" +checkCommitReadiness 2 "\"Org1MSP\": true" "\"Org2MSP\": true" + +## now that we know for sure both orgs have approved, commit the definition +commitChaincodeDefinition 1 2 + +## query on both orgs to see that the definition committed successfully +queryCommitted 1 +queryCommitted 2 + +# start the container +startDockerContainer + +## Invoke the chaincode - this does require that the chaincode have the 'initLedger' +## method defined +if [ "$CC_INIT_FCN" = "NA" ]; then + infoln "Chaincode initialization is not required" +else + chaincodeInvokeInit 1 2 +fi + +exit 0 diff --git a/test-network/scripts/pkgcc.sh b/test-network/scripts/pkgcc.sh new file mode 100755 index 00000000..6b89461f --- /dev/null +++ b/test-network/scripts/pkgcc.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +# +# SPDX-License-Identifier: Apache-2.0 +# + +function usage() { + echo "Usage: pkgcc.sh -l